blob: c7940c900488e031a1b341a42a33feed9961885a [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
37}
38
39type Service struct {
40 Name string
41 HwAddress net.HardwareAddr
42 Onu *Onu
43 CTag int
44 STag int
45 NeedsEapol bool
46 NeedsDhcp bool
47 NeedsIgmp bool
48 TechnologyProfileID int
49 UniTagMatch int
50 ConfigureMacAddress bool
51 UsPonCTagPriority int
52 UsPonSTagPriority int
53 DsPonCTagPriority int
54 DsPonSTagPriority int
55
56 // state
57 GemPort uint32
58 EapolState *fsm.FSM
59 DHCPState *fsm.FSM
60 PacketCh chan OnuPacketMessage
61}
62
63func NewService(name string, hwAddress net.HardwareAddr, onu *Onu, cTag int, sTag int,
64 needsEapol bool, needsDchp bool, needsIgmp bool, tpID int, uniTagMatch int, configMacAddress bool,
65 usPonCTagPriority int, usPonSTagPriority int, dsPonCTagPriority int, dsPonSTagPriority int) (*Service, error) {
66
67 service := Service{
68 Name: name,
69 HwAddress: hwAddress,
70 Onu: onu,
71 CTag: cTag,
72 STag: sTag,
73 NeedsEapol: needsEapol,
74 NeedsDhcp: needsDchp,
75 NeedsIgmp: needsIgmp,
76 TechnologyProfileID: tpID,
77 UniTagMatch: uniTagMatch,
78 ConfigureMacAddress: configMacAddress,
79 UsPonCTagPriority: usPonCTagPriority,
80 UsPonSTagPriority: usPonSTagPriority,
81 DsPonCTagPriority: dsPonCTagPriority,
82 DsPonSTagPriority: dsPonSTagPriority,
83 PacketCh: make(chan OnuPacketMessage),
84 }
85
86 service.EapolState = fsm.NewFSM(
87 "created",
88 fsm.Events{
89 {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"},
90 {Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
91 {Name: "eap_response_identity_sent", Src: []string{"eap_start_sent"}, Dst: "eap_response_identity_sent"},
92 {Name: "eap_response_challenge_sent", Src: []string{"eap_response_identity_sent"}, Dst: "eap_response_challenge_sent"},
93 {Name: "eap_response_success_received", Src: []string{"eap_response_challenge_sent"}, Dst: "eap_response_success_received"},
94 {Name: "auth_failed", Src: []string{"auth_started", "eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent"}, Dst: "auth_failed"},
95 },
96 fsm.Callbacks{
97 "enter_state": func(e *fsm.Event) {
98 service.logStateChange("EapolState", e.Src, e.Dst)
99 },
100 },
101 )
102
103 service.DHCPState = fsm.NewFSM(
104 "created",
105 fsm.Events{
106 {Name: "start_dhcp", Src: []string{"created", "eap_response_success_received", "dhcp_discovery_sent", "dhcp_request_sent", "dhcp_ack_received", "dhcp_failed"}, Dst: "dhcp_started"},
107 {Name: "dhcp_discovery_sent", Src: []string{"dhcp_started"}, Dst: "dhcp_discovery_sent"},
108 {Name: "dhcp_request_sent", Src: []string{"dhcp_discovery_sent"}, Dst: "dhcp_request_sent"},
109 {Name: "dhcp_ack_received", Src: []string{"dhcp_request_sent"}, Dst: "dhcp_ack_received"},
110 {Name: "dhcp_failed", Src: []string{"dhcp_started", "dhcp_discovery_sent", "dhcp_request_sent"}, Dst: "dhcp_failed"},
111 },
112 fsm.Callbacks{
113 "enter_state": func(e *fsm.Event) {
114 service.logStateChange("DHCPState", e.Src, e.Dst)
115 },
116 },
117 )
118
119 return &service, nil
120}
121
122func (s *Service) HandleAuth(stream bbsimTypes.Stream) {
123
124 if !s.NeedsEapol {
125 serviceLogger.WithFields(log.Fields{
126 "OnuId": s.Onu.ID,
127 "IntfId": s.Onu.PonPortID,
128 "OnuSn": s.Onu.Sn(),
129 "Name": s.Name,
130 "NeedsEapol": s.NeedsEapol,
131 }).Debug("Won't start authentication as EAPOL is not required")
132 return
133 }
134
135 // TODO check if the EAPOL flow was received before starting auth
136
137 if err := s.EapolState.Event("start_auth"); err != nil {
138 serviceLogger.WithFields(log.Fields{
139 "OnuId": s.Onu.ID,
140 "IntfId": s.Onu.PonPortID,
141 "OnuSn": s.Onu.Sn(),
142 "Name": s.Name,
143 "err": err.Error(),
144 }).Error("Can't start auth for this Service")
145 } else {
146 if err := s.handleEapolStart(stream); err != nil {
147 serviceLogger.WithFields(log.Fields{
148 "OnuId": s.Onu.ID,
149 "IntfId": s.Onu.PonPortID,
150 "OnuSn": s.Onu.Sn(),
151 "Name": s.Name,
152 "err": err,
153 }).Error("Error while sending EapolStart packet")
154 _ = s.EapolState.Event("auth_failed")
155 }
156 }
157}
158
159func (s *Service) HandleDhcp(stream bbsimTypes.Stream, cTag int) {
160
161 // FIXME start dhcp only for the Service that matches the tag
162 if s.CTag != cTag {
163 serviceLogger.WithFields(log.Fields{
164 "OnuId": s.Onu.ID,
165 "IntfId": s.Onu.PonPortID,
166 "OnuSn": s.Onu.Sn(),
167 "Name": s.Name,
168 }).Debug("DHCP flow is not for this service, ignoring")
169 return
170 }
171
172 // NOTE since we're matching the flow tag, this may not be required
173 if !s.NeedsDhcp {
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 "NeedsDhcp": s.NeedsDhcp,
180 }).Debug("Won't start DHCP as it is not required")
181 return
182 }
183
184 // TODO check if the EAPOL flow was received before starting auth
185
186 if err := s.DHCPState.Event("start_dhcp"); err != nil {
187 serviceLogger.WithFields(log.Fields{
188 "OnuId": s.Onu.ID,
189 "IntfId": s.Onu.PonPortID,
190 "OnuSn": s.Onu.Sn(),
191 "Name": s.Name,
192 "err": err.Error(),
193 }).Error("Can't start DHCP for this Service")
194 } else {
195 if err := s.handleDHCPStart(stream); err != nil {
196 serviceLogger.WithFields(log.Fields{
197 "OnuId": s.Onu.ID,
198 "IntfId": s.Onu.PonPortID,
199 "OnuSn": s.Onu.Sn(),
200 "Name": s.Name,
201 "err": err,
202 }).Error("Error while sending DHCPDiscovery packet")
203 _ = s.DHCPState.Event("dhcp_failed")
204 }
205 }
206}
207
208func (s *Service) handleEapolStart(stream bbsimTypes.Stream) error {
209
210 serviceLogger.WithFields(log.Fields{
211 "OnuId": s.Onu.ID,
212 "IntfId": s.Onu.PonPortID,
213 "OnuSn": s.Onu.Sn(),
214 "GemPort": s.GemPort,
215 "Name": s.Name,
216 }).Debugf("handleEapolStart")
217
218 if err := eapol.SendEapStart(s.Onu.ID, s.Onu.PonPortID, s.Onu.Sn(), s.Onu.PortNo,
219 s.HwAddress, s.GemPort, s.EapolState, stream); err != nil {
220 serviceLogger.WithFields(log.Fields{
221 "OnuId": s.Onu.ID,
222 "IntfId": s.Onu.PonPortID,
223 "OnuSn": s.Onu.Sn(),
224 "GemPort": s.GemPort,
225 "Name": s.Name,
226 }).Error("handleEapolStart")
227 return err
228 }
229 return nil
230}
231
232func (s *Service) handleDHCPStart(stream bbsimTypes.Stream) error {
233
234 serviceLogger.WithFields(log.Fields{
235 "OnuId": s.Onu.ID,
236 "IntfId": s.Onu.PonPortID,
237 "OnuSn": s.Onu.Sn(),
238 "Name": s.Name,
239 "GemPortId": s.GemPort,
240 }).Debugf("HandleDHCPStart")
241
242 if err := dhcp.SendDHCPDiscovery(s.Onu.PonPort.Olt.ID, s.Onu.PonPortID, s.Onu.ID, int(s.CTag), s.GemPort,
243 s.Onu.Sn(), s.Onu.PortNo, s.DHCPState, s.HwAddress, stream); err != nil {
244 serviceLogger.WithFields(log.Fields{
245 "OnuId": s.Onu.ID,
246 "IntfId": s.Onu.PonPortID,
247 "OnuSn": s.Onu.Sn(),
248 "Name": s.Name,
249 "GemPortId": s.GemPort,
250 }).Error("HandleDHCPStart")
251 return err
252 }
253 return nil
254}
255
256func (s *Service) HandlePackets(stream bbsimTypes.Stream) {
257 serviceLogger.WithFields(log.Fields{
258 "OnuId": s.Onu.ID,
259 "IntfId": s.Onu.PonPortID,
260 "OnuSn": s.Onu.Sn(),
261 "GemPortId": s.GemPort,
262 "Name": s.Name,
263 }).Debug("Listening on Service Packet Channel")
264
265 defer func() {
266 serviceLogger.WithFields(log.Fields{
267 "OnuId": s.Onu.ID,
268 "IntfId": s.Onu.PonPortID,
269 "OnuSn": s.Onu.Sn(),
270 "GemPortId": s.GemPort,
271 "Name": s.Name,
272 }).Debug("Done Listening on Service Packet Channel")
273 }()
274
275 for msg := range s.PacketCh {
276 serviceLogger.WithFields(log.Fields{
277 "OnuId": s.Onu.ID,
278 "IntfId": s.Onu.PonPortID,
279 "OnuSn": s.Onu.Sn(),
280 "Name": s.Name,
281 "messageType": msg.Type,
282 }).Debug("Received message on Service Packet Channel")
283
284 if msg.Type == packetHandlers.EAPOL {
285 eapol.HandleNextPacket(msg.OnuId, msg.IntfId, s.GemPort, s.Onu.Sn(), s.Onu.PortNo, s.EapolState, msg.Packet, stream, nil)
286 } else if msg.Type == packetHandlers.DHCP {
287 _ = 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)
288 }
289 }
290}
291
292func (s *Service) logStateChange(stateMachine string, src string, dst string) {
293 serviceLogger.WithFields(log.Fields{
294 "OnuId": s.Onu.ID,
295 "IntfId": s.Onu.PonPortID,
296 "OnuSn": s.Onu.Sn(),
297 "Name": s.Name,
298 }).Debugf("Changing Service.%s InternalState from %s to %s", stateMachine, src, dst)
299}