blob: 15d313a09131fdc3b1bd5425c53119480ae3bd5f [file] [log] [blame]
Matteo Scandolo4a036262020-08-17 15:56:13 -07001/*
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 "github.com/looplab/fsm"
21 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
22 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
23 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
24 bbsimTypes "github.com/opencord/bbsim/internal/bbsim/types"
25 log "github.com/sirupsen/logrus"
26 "net"
27)
28
29var serviceLogger = log.WithFields(log.Fields{
30 "module": "SERVICE",
31})
32
33type ServiceIf interface {
34 HandlePackets(stream bbsimTypes.Stream) // start listening on the PacketCh
35 HandleAuth(stream bbsimTypes.Stream) // Sends the EapoStart packet
36 HandleDhcp(stream bbsimTypes.Stream, cTag int) // Sends the DHCPDiscover packet
Matteo Scandolo75ed5b92020-09-03 09:03:16 -070037
38 Initialize()
39 Disable()
Matteo Scandolo4a036262020-08-17 15:56:13 -070040}
41
42type Service struct {
43 Name string
44 HwAddress net.HardwareAddr
45 Onu *Onu
46 CTag int
47 STag int
48 NeedsEapol bool
49 NeedsDhcp bool
50 NeedsIgmp bool
51 TechnologyProfileID int
52 UniTagMatch int
53 ConfigureMacAddress bool
54 UsPonCTagPriority int
55 UsPonSTagPriority int
56 DsPonCTagPriority int
57 DsPonSTagPriority int
58
59 // state
Matteo Scandolo75ed5b92020-09-03 09:03:16 -070060 GemPort uint32
61 InternalState *fsm.FSM
62 EapolState *fsm.FSM
63 DHCPState *fsm.FSM
64 PacketCh chan OnuPacketMessage
Matteo Scandolo4a036262020-08-17 15:56:13 -070065}
66
67func NewService(name string, hwAddress net.HardwareAddr, onu *Onu, cTag int, sTag int,
68 needsEapol bool, needsDchp bool, needsIgmp bool, tpID int, uniTagMatch int, configMacAddress bool,
69 usPonCTagPriority int, usPonSTagPriority int, dsPonCTagPriority int, dsPonSTagPriority int) (*Service, error) {
70
71 service := Service{
72 Name: name,
73 HwAddress: hwAddress,
74 Onu: onu,
75 CTag: cTag,
76 STag: sTag,
77 NeedsEapol: needsEapol,
78 NeedsDhcp: needsDchp,
79 NeedsIgmp: needsIgmp,
80 TechnologyProfileID: tpID,
81 UniTagMatch: uniTagMatch,
82 ConfigureMacAddress: configMacAddress,
83 UsPonCTagPriority: usPonCTagPriority,
84 UsPonSTagPriority: usPonSTagPriority,
85 DsPonCTagPriority: dsPonCTagPriority,
86 DsPonSTagPriority: dsPonSTagPriority,
Matteo Scandolo4a036262020-08-17 15:56:13 -070087 }
88
Matteo Scandolo75ed5b92020-09-03 09:03:16 -070089 service.InternalState = fsm.NewFSM(
90 "created",
91 fsm.Events{
92 {Name: "initialized", Src: []string{"created", "disabled"}, Dst: "initialized"},
93 {Name: "disabled", Src: []string{"initialized"}, Dst: "disabled"},
94 },
95 fsm.Callbacks{
96 "enter_state": func(e *fsm.Event) {
97 service.logStateChange("InternalState", e.Src, e.Dst)
98 },
99 "enter_initialized": func(e *fsm.Event) {
100 service.PacketCh = make(chan OnuPacketMessage)
101 },
102 "enter_disabled": func(e *fsm.Event) {
103 // reset the state machines
104 service.EapolState.SetState("created")
105 service.DHCPState.SetState("created")
106
107 // stop listening for packets
108 close(service.PacketCh)
109 },
110 },
111 )
112
Matteo Scandolo4a036262020-08-17 15:56:13 -0700113 service.EapolState = fsm.NewFSM(
114 "created",
115 fsm.Events{
116 {Name: "start_auth", Src: []string{"created", "eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent", "eap_response_success_received", "auth_failed"}, Dst: "auth_started"},
117 {Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
118 {Name: "eap_response_identity_sent", Src: []string{"eap_start_sent"}, Dst: "eap_response_identity_sent"},
119 {Name: "eap_response_challenge_sent", Src: []string{"eap_response_identity_sent"}, Dst: "eap_response_challenge_sent"},
120 {Name: "eap_response_success_received", Src: []string{"eap_response_challenge_sent"}, Dst: "eap_response_success_received"},
121 {Name: "auth_failed", Src: []string{"auth_started", "eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent"}, Dst: "auth_failed"},
122 },
123 fsm.Callbacks{
124 "enter_state": func(e *fsm.Event) {
125 service.logStateChange("EapolState", e.Src, e.Dst)
126 },
127 },
128 )
129
130 service.DHCPState = fsm.NewFSM(
131 "created",
132 fsm.Events{
133 {Name: "start_dhcp", Src: []string{"created", "eap_response_success_received", "dhcp_discovery_sent", "dhcp_request_sent", "dhcp_ack_received", "dhcp_failed"}, Dst: "dhcp_started"},
134 {Name: "dhcp_discovery_sent", Src: []string{"dhcp_started"}, Dst: "dhcp_discovery_sent"},
135 {Name: "dhcp_request_sent", Src: []string{"dhcp_discovery_sent"}, Dst: "dhcp_request_sent"},
136 {Name: "dhcp_ack_received", Src: []string{"dhcp_request_sent"}, Dst: "dhcp_ack_received"},
137 {Name: "dhcp_failed", Src: []string{"dhcp_started", "dhcp_discovery_sent", "dhcp_request_sent"}, Dst: "dhcp_failed"},
138 },
139 fsm.Callbacks{
140 "enter_state": func(e *fsm.Event) {
141 service.logStateChange("DHCPState", e.Src, e.Dst)
142 },
143 },
144 )
145
146 return &service, nil
147}
148
149func (s *Service) HandleAuth(stream bbsimTypes.Stream) {
150
151 if !s.NeedsEapol {
152 serviceLogger.WithFields(log.Fields{
153 "OnuId": s.Onu.ID,
154 "IntfId": s.Onu.PonPortID,
155 "OnuSn": s.Onu.Sn(),
156 "Name": s.Name,
157 "NeedsEapol": s.NeedsEapol,
158 }).Debug("Won't start authentication as EAPOL is not required")
159 return
160 }
161
162 // TODO check if the EAPOL flow was received before starting auth
163
164 if err := s.EapolState.Event("start_auth"); err != nil {
165 serviceLogger.WithFields(log.Fields{
166 "OnuId": s.Onu.ID,
167 "IntfId": s.Onu.PonPortID,
168 "OnuSn": s.Onu.Sn(),
169 "Name": s.Name,
170 "err": err.Error(),
171 }).Error("Can't start auth for this Service")
172 } else {
173 if err := s.handleEapolStart(stream); err != nil {
174 serviceLogger.WithFields(log.Fields{
175 "OnuId": s.Onu.ID,
176 "IntfId": s.Onu.PonPortID,
177 "OnuSn": s.Onu.Sn(),
178 "Name": s.Name,
179 "err": err,
180 }).Error("Error while sending EapolStart packet")
181 _ = s.EapolState.Event("auth_failed")
182 }
183 }
184}
185
186func (s *Service) HandleDhcp(stream bbsimTypes.Stream, cTag int) {
187
Matteo Scandolo4a036262020-08-17 15:56:13 -0700188 if s.CTag != cTag {
189 serviceLogger.WithFields(log.Fields{
190 "OnuId": s.Onu.ID,
191 "IntfId": s.Onu.PonPortID,
192 "OnuSn": s.Onu.Sn(),
193 "Name": s.Name,
194 }).Debug("DHCP flow is not for this service, ignoring")
195 return
196 }
197
198 // NOTE since we're matching the flow tag, this may not be required
199 if !s.NeedsDhcp {
200 serviceLogger.WithFields(log.Fields{
201 "OnuId": s.Onu.ID,
202 "IntfId": s.Onu.PonPortID,
203 "OnuSn": s.Onu.Sn(),
204 "Name": s.Name,
205 "NeedsDhcp": s.NeedsDhcp,
206 }).Debug("Won't start DHCP as it is not required")
207 return
208 }
209
210 // TODO check if the EAPOL flow was received before starting auth
211
212 if err := s.DHCPState.Event("start_dhcp"); err != nil {
213 serviceLogger.WithFields(log.Fields{
214 "OnuId": s.Onu.ID,
215 "IntfId": s.Onu.PonPortID,
216 "OnuSn": s.Onu.Sn(),
217 "Name": s.Name,
218 "err": err.Error(),
219 }).Error("Can't start DHCP for this Service")
220 } else {
221 if err := s.handleDHCPStart(stream); err != nil {
222 serviceLogger.WithFields(log.Fields{
223 "OnuId": s.Onu.ID,
224 "IntfId": s.Onu.PonPortID,
225 "OnuSn": s.Onu.Sn(),
226 "Name": s.Name,
227 "err": err,
228 }).Error("Error while sending DHCPDiscovery packet")
229 _ = s.DHCPState.Event("dhcp_failed")
230 }
231 }
232}
233
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700234func (s *Service) HandlePackets(stream bbsimTypes.Stream) {
235 serviceLogger.WithFields(log.Fields{
236 "OnuId": s.Onu.ID,
237 "IntfId": s.Onu.PonPortID,
238 "OnuSn": s.Onu.Sn(),
239 "GemPortId": s.GemPort,
240 "Name": s.Name,
241 }).Debug("Listening on Service Packet Channel")
242
243 defer func() {
244 serviceLogger.WithFields(log.Fields{
245 "OnuId": s.Onu.ID,
246 "IntfId": s.Onu.PonPortID,
247 "OnuSn": s.Onu.Sn(),
248 "GemPortId": s.GemPort,
249 "Name": s.Name,
250 }).Debug("Done Listening on Service Packet Channel")
251 }()
252
253 for msg := range s.PacketCh {
254 serviceLogger.WithFields(log.Fields{
255 "OnuId": s.Onu.ID,
256 "IntfId": s.Onu.PonPortID,
257 "OnuSn": s.Onu.Sn(),
258 "Name": s.Name,
259 "messageType": msg.Type,
260 }).Debug("Received message on Service Packet Channel")
261
262 if msg.Type == packetHandlers.EAPOL {
263 eapol.HandleNextPacket(msg.OnuId, msg.IntfId, s.GemPort, s.Onu.Sn(), s.Onu.PortNo, s.EapolState, msg.Packet, stream, nil)
264 } else if msg.Type == packetHandlers.DHCP {
265 _ = dhcp.HandleNextPacket(s.Onu.PonPort.Olt.ID, s.Onu.ID, s.Onu.PonPortID, s.Onu.Sn(), s.Onu.PortNo, s.CTag, s.GemPort, s.HwAddress, s.DHCPState, msg.Packet, stream)
266 }
267 }
268}
269
270func (s *Service) Initialize() {
271 if err := s.InternalState.Event("initialized"); err != nil {
272 serviceLogger.WithFields(log.Fields{
273 "OnuId": s.Onu.ID,
274 "IntfId": s.Onu.PonPortID,
275 "OnuSn": s.Onu.Sn(),
276 "Name": s.Name,
277 "Err": err,
278 }).Error("Cannot initialize service")
279 }
280}
281
282func (s *Service) Disable() {
283 if err := s.InternalState.Event("disabled"); err != nil {
284 serviceLogger.WithFields(log.Fields{
285 "OnuId": s.Onu.ID,
286 "IntfId": s.Onu.PonPortID,
287 "OnuSn": s.Onu.Sn(),
288 "Name": s.Name,
289 "Err": err,
290 }).Error("Cannot disable service")
291 }
292}
293
Matteo Scandolo4a036262020-08-17 15:56:13 -0700294func (s *Service) handleEapolStart(stream bbsimTypes.Stream) error {
295
296 serviceLogger.WithFields(log.Fields{
297 "OnuId": s.Onu.ID,
298 "IntfId": s.Onu.PonPortID,
299 "OnuSn": s.Onu.Sn(),
300 "GemPort": s.GemPort,
301 "Name": s.Name,
302 }).Debugf("handleEapolStart")
303
304 if err := eapol.SendEapStart(s.Onu.ID, s.Onu.PonPortID, s.Onu.Sn(), s.Onu.PortNo,
305 s.HwAddress, s.GemPort, s.EapolState, stream); err != nil {
306 serviceLogger.WithFields(log.Fields{
307 "OnuId": s.Onu.ID,
308 "IntfId": s.Onu.PonPortID,
309 "OnuSn": s.Onu.Sn(),
310 "GemPort": s.GemPort,
311 "Name": s.Name,
312 }).Error("handleEapolStart")
313 return err
314 }
315 return nil
316}
317
318func (s *Service) handleDHCPStart(stream bbsimTypes.Stream) error {
319
320 serviceLogger.WithFields(log.Fields{
321 "OnuId": s.Onu.ID,
322 "IntfId": s.Onu.PonPortID,
323 "OnuSn": s.Onu.Sn(),
324 "Name": s.Name,
325 "GemPortId": s.GemPort,
326 }).Debugf("HandleDHCPStart")
327
328 if err := dhcp.SendDHCPDiscovery(s.Onu.PonPort.Olt.ID, s.Onu.PonPortID, s.Onu.ID, int(s.CTag), s.GemPort,
329 s.Onu.Sn(), s.Onu.PortNo, s.DHCPState, s.HwAddress, stream); err != nil {
330 serviceLogger.WithFields(log.Fields{
331 "OnuId": s.Onu.ID,
332 "IntfId": s.Onu.PonPortID,
333 "OnuSn": s.Onu.Sn(),
334 "Name": s.Name,
335 "GemPortId": s.GemPort,
336 }).Error("HandleDHCPStart")
337 return err
338 }
339 return nil
340}
341
Matteo Scandolo4a036262020-08-17 15:56:13 -0700342func (s *Service) logStateChange(stateMachine string, src string, dst string) {
343 serviceLogger.WithFields(log.Fields{
344 "OnuId": s.Onu.ID,
345 "IntfId": s.Onu.PonPortID,
346 "OnuSn": s.Onu.Sn(),
347 "Name": s.Name,
348 }).Debugf("Changing Service.%s InternalState from %s to %s", stateMachine, src, dst)
349}