blob: bee306530850fd5cabe9328790a355317e87e2eb [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{
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 {
Matteo Scandolo8d281372020-09-03 16:23:37 -0700265 _ = 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, s.UsPonCTagPriority, stream)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700266 }
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,
Matteo Scandolo8d281372020-09-03 16:23:37 -0700329 s.Onu.Sn(), s.Onu.PortNo, s.DHCPState, s.HwAddress, s.UsPonCTagPriority, stream); err != nil {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700330 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}