blob: 360bd4adb8c41a52ab9e81a329b1a5e97941ab75 [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
Matteo Scandolo8d281372020-09-03 16:23:37 -070054 UsPonCTagPriority uint8
55 UsPonSTagPriority uint8
56 DsPonCTagPriority uint8
57 DsPonSTagPriority uint8
Matteo Scandolo4a036262020-08-17 15:56:13 -070058
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,
Matteo Scandolo8d281372020-09-03 16:23:37 -070069 usPonCTagPriority uint8, usPonSTagPriority uint8, dsPonCTagPriority uint8, dsPonSTagPriority uint8) (*Service, error) {
Matteo Scandolo4a036262020-08-17 15:56:13 -070070
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{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700133 // TODO only allow transitions to dhcp_start from success or failure, not in-between states
134 // TODO forcefully fail DHCP if we don't get an ack in X seconds
135 {Name: "start_dhcp", Src: []string{"created", "dhcp_discovery_sent", "dhcp_request_sent", "dhcp_ack_received", "dhcp_failed"}, Dst: "dhcp_started"},
Matteo Scandolo4a036262020-08-17 15:56:13 -0700136 {Name: "dhcp_discovery_sent", Src: []string{"dhcp_started"}, Dst: "dhcp_discovery_sent"},
137 {Name: "dhcp_request_sent", Src: []string{"dhcp_discovery_sent"}, Dst: "dhcp_request_sent"},
138 {Name: "dhcp_ack_received", Src: []string{"dhcp_request_sent"}, Dst: "dhcp_ack_received"},
139 {Name: "dhcp_failed", Src: []string{"dhcp_started", "dhcp_discovery_sent", "dhcp_request_sent"}, Dst: "dhcp_failed"},
140 },
141 fsm.Callbacks{
142 "enter_state": func(e *fsm.Event) {
143 service.logStateChange("DHCPState", e.Src, e.Dst)
144 },
145 },
146 )
147
148 return &service, nil
149}
150
151func (s *Service) HandleAuth(stream bbsimTypes.Stream) {
152
153 if !s.NeedsEapol {
154 serviceLogger.WithFields(log.Fields{
155 "OnuId": s.Onu.ID,
156 "IntfId": s.Onu.PonPortID,
157 "OnuSn": s.Onu.Sn(),
158 "Name": s.Name,
159 "NeedsEapol": s.NeedsEapol,
160 }).Debug("Won't start authentication as EAPOL is not required")
161 return
162 }
163
164 // TODO check if the EAPOL flow was received before starting auth
165
166 if err := s.EapolState.Event("start_auth"); err != nil {
167 serviceLogger.WithFields(log.Fields{
168 "OnuId": s.Onu.ID,
169 "IntfId": s.Onu.PonPortID,
170 "OnuSn": s.Onu.Sn(),
171 "Name": s.Name,
172 "err": err.Error(),
173 }).Error("Can't start auth for this Service")
174 } else {
175 if err := s.handleEapolStart(stream); err != nil {
176 serviceLogger.WithFields(log.Fields{
177 "OnuId": s.Onu.ID,
178 "IntfId": s.Onu.PonPortID,
179 "OnuSn": s.Onu.Sn(),
180 "Name": s.Name,
181 "err": err,
182 }).Error("Error while sending EapolStart packet")
183 _ = s.EapolState.Event("auth_failed")
184 }
185 }
186}
187
188func (s *Service) HandleDhcp(stream bbsimTypes.Stream, cTag int) {
189
Matteo Scandolo4a036262020-08-17 15:56:13 -0700190 if s.CTag != cTag {
191 serviceLogger.WithFields(log.Fields{
192 "OnuId": s.Onu.ID,
193 "IntfId": s.Onu.PonPortID,
194 "OnuSn": s.Onu.Sn(),
195 "Name": s.Name,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700196 }).Trace("DHCP flow is not for this service, ignoring")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700197 return
198 }
199
Matteo Scandolo4a036262020-08-17 15:56:13 -0700200 if !s.NeedsDhcp {
201 serviceLogger.WithFields(log.Fields{
202 "OnuId": s.Onu.ID,
203 "IntfId": s.Onu.PonPortID,
204 "OnuSn": s.Onu.Sn(),
205 "Name": s.Name,
206 "NeedsDhcp": s.NeedsDhcp,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700207 }).Trace("Won't start DHCP as it is not required")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700208 return
209 }
210
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700211 // TODO check if the DHCP flow was received before starting auth
Matteo Scandolo4a036262020-08-17 15:56:13 -0700212
213 if err := s.DHCPState.Event("start_dhcp"); err != nil {
214 serviceLogger.WithFields(log.Fields{
215 "OnuId": s.Onu.ID,
216 "IntfId": s.Onu.PonPortID,
217 "OnuSn": s.Onu.Sn(),
218 "Name": s.Name,
219 "err": err.Error(),
220 }).Error("Can't start DHCP for this Service")
221 } else {
222 if err := s.handleDHCPStart(stream); err != nil {
223 serviceLogger.WithFields(log.Fields{
224 "OnuId": s.Onu.ID,
225 "IntfId": s.Onu.PonPortID,
226 "OnuSn": s.Onu.Sn(),
227 "Name": s.Name,
228 "err": err,
229 }).Error("Error while sending DHCPDiscovery packet")
230 _ = s.DHCPState.Event("dhcp_failed")
231 }
232 }
233}
234
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700235func (s *Service) HandlePackets(stream bbsimTypes.Stream) {
236 serviceLogger.WithFields(log.Fields{
237 "OnuId": s.Onu.ID,
238 "IntfId": s.Onu.PonPortID,
239 "OnuSn": s.Onu.Sn(),
240 "GemPortId": s.GemPort,
241 "Name": s.Name,
242 }).Debug("Listening on Service Packet Channel")
243
244 defer func() {
245 serviceLogger.WithFields(log.Fields{
246 "OnuId": s.Onu.ID,
247 "IntfId": s.Onu.PonPortID,
248 "OnuSn": s.Onu.Sn(),
249 "GemPortId": s.GemPort,
250 "Name": s.Name,
251 }).Debug("Done Listening on Service Packet Channel")
252 }()
253
254 for msg := range s.PacketCh {
255 serviceLogger.WithFields(log.Fields{
256 "OnuId": s.Onu.ID,
257 "IntfId": s.Onu.PonPortID,
258 "OnuSn": s.Onu.Sn(),
259 "Name": s.Name,
260 "messageType": msg.Type,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700261 }).Trace("Received message on Service Packet Channel")
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700262
263 if msg.Type == packetHandlers.EAPOL {
264 eapol.HandleNextPacket(msg.OnuId, msg.IntfId, s.GemPort, s.Onu.Sn(), s.Onu.PortNo, s.EapolState, msg.Packet, stream, nil)
265 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700266 _ = dhcp.HandleNextPacket(s.Onu.PonPort.Olt.ID, s.Onu.ID, s.Onu.PonPortID, s.Name, s.Onu.Sn(), s.Onu.PortNo, s.CTag, s.GemPort, s.HwAddress, s.DHCPState, msg.Packet, s.UsPonCTagPriority, stream)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700267 }
268 }
269}
270
271func (s *Service) Initialize() {
272 if err := s.InternalState.Event("initialized"); err != nil {
273 serviceLogger.WithFields(log.Fields{
274 "OnuId": s.Onu.ID,
275 "IntfId": s.Onu.PonPortID,
276 "OnuSn": s.Onu.Sn(),
277 "Name": s.Name,
278 "Err": err,
279 }).Error("Cannot initialize service")
280 }
281}
282
283func (s *Service) Disable() {
284 if err := s.InternalState.Event("disabled"); err != nil {
285 serviceLogger.WithFields(log.Fields{
286 "OnuId": s.Onu.ID,
287 "IntfId": s.Onu.PonPortID,
288 "OnuSn": s.Onu.Sn(),
289 "Name": s.Name,
290 "Err": err,
291 }).Error("Cannot disable service")
292 }
293}
294
Matteo Scandolo4a036262020-08-17 15:56:13 -0700295func (s *Service) handleEapolStart(stream bbsimTypes.Stream) error {
296
297 serviceLogger.WithFields(log.Fields{
298 "OnuId": s.Onu.ID,
299 "IntfId": s.Onu.PonPortID,
300 "OnuSn": s.Onu.Sn(),
301 "GemPort": s.GemPort,
302 "Name": s.Name,
303 }).Debugf("handleEapolStart")
304
305 if err := eapol.SendEapStart(s.Onu.ID, s.Onu.PonPortID, s.Onu.Sn(), s.Onu.PortNo,
306 s.HwAddress, s.GemPort, s.EapolState, stream); err != nil {
307 serviceLogger.WithFields(log.Fields{
308 "OnuId": s.Onu.ID,
309 "IntfId": s.Onu.PonPortID,
310 "OnuSn": s.Onu.Sn(),
311 "GemPort": s.GemPort,
312 "Name": s.Name,
313 }).Error("handleEapolStart")
314 return err
315 }
316 return nil
317}
318
319func (s *Service) handleDHCPStart(stream bbsimTypes.Stream) error {
320
321 serviceLogger.WithFields(log.Fields{
322 "OnuId": s.Onu.ID,
323 "IntfId": s.Onu.PonPortID,
324 "OnuSn": s.Onu.Sn(),
325 "Name": s.Name,
326 "GemPortId": s.GemPort,
327 }).Debugf("HandleDHCPStart")
328
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700329 if err := dhcp.SendDHCPDiscovery(s.Onu.PonPort.Olt.ID, s.Onu.PonPortID, s.Onu.ID, s.Name, int(s.CTag), s.GemPort,
Matteo Scandolo8d281372020-09-03 16:23:37 -0700330 s.Onu.Sn(), s.Onu.PortNo, s.DHCPState, s.HwAddress, s.UsPonCTagPriority, stream); err != nil {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700331 serviceLogger.WithFields(log.Fields{
332 "OnuId": s.Onu.ID,
333 "IntfId": s.Onu.PonPortID,
334 "OnuSn": s.Onu.Sn(),
335 "Name": s.Name,
336 "GemPortId": s.GemPort,
337 }).Error("HandleDHCPStart")
338 return err
339 }
340 return nil
341}
342
Matteo Scandolo4a036262020-08-17 15:56:13 -0700343func (s *Service) logStateChange(stateMachine string, src string, dst string) {
344 serviceLogger.WithFields(log.Fields{
345 "OnuId": s.Onu.ID,
346 "IntfId": s.Onu.PonPortID,
347 "OnuSn": s.Onu.Sn(),
348 "Name": s.Name,
349 }).Debugf("Changing Service.%s InternalState from %s to %s", stateMachine, src, dst)
350}