blob: 09164219a796912e34d2a95b8e3f4dc5acc188f0 [file] [log] [blame]
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -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 dhcp
18
19import (
Matteo Scandolo40e067f2019-10-16 16:59:41 -070020 "context"
Matteo Scandolo8d281372020-09-03 16:23:37 -070021 "encoding/hex"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070022 "errors"
23 "fmt"
24 "github.com/google/gopacket"
25 "github.com/google/gopacket/layers"
26 "github.com/looplab/fsm"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070027 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070028 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070029 "github.com/opencord/voltha-protos/v4/go/openolt"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070030 log "github.com/sirupsen/logrus"
Matteo Scandolo24a88c42020-09-17 14:55:28 -070031 "net"
32 "reflect"
33 "strconv"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070034)
35
36var dhcpLogger = log.WithFields(log.Fields{
37 "module": "DHCP",
38})
39
40var defaultParamsRequestList = []layers.DHCPOpt{
41 layers.DHCPOptSubnetMask,
42 layers.DHCPOptBroadcastAddr,
43 layers.DHCPOptTimeOffset,
44 layers.DHCPOptRouter,
45 layers.DHCPOptDomainName,
46 layers.DHCPOptDNS,
47 layers.DHCPOptDomainSearch,
48 layers.DHCPOptHostname,
49 layers.DHCPOptNetBIOSTCPNS,
50 layers.DHCPOptNetBIOSTCPScope,
51 layers.DHCPOptInterfaceMTU,
52 layers.DHCPOptClasslessStaticRoute,
53 layers.DHCPOptNTPServers,
54}
55
Matteo Scandolo24a88c42020-09-17 14:55:28 -070056func macAddressToTxId(mac net.HardwareAddr) uint32 {
57
58 // NOTE we want to generate a unique XID,
59 // the easiest way is to transform the macAddress (already unique) into an integer
60 str := ""
61 for _, i := range mac {
62 str = str + fmt.Sprintf("%d", i)
63 }
64 xid, err := strconv.Atoi(str)
Matteo Scandolofe9ac252019-10-25 11:40:17 -070065 if err != nil {
66 log.Fatal("Can't generate unique XID for ONU")
67 }
68
Matteo Scandolo24a88c42020-09-17 14:55:28 -070069 return uint32(xid)
70}
71
72func createDefaultDHCPReq(mac net.HardwareAddr) layers.DHCPv4 {
73 xid := macAddressToTxId(mac)
74
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070075 return layers.DHCPv4{
76 Operation: layers.DHCPOpRequest,
77 HardwareType: layers.LinkTypeEthernet,
78 HardwareLen: 6,
79 HardwareOpts: 0,
Matteo Scandolofe9ac252019-10-25 11:40:17 -070080 Xid: uint32(xid),
Matteo Scandolo40e067f2019-10-16 16:59:41 -070081 ClientHWAddr: mac,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070082 }
83}
84
Matteo Scandolobfcfbb32020-09-28 14:14:39 -070085func createDefaultOpts(gemPortId uint32, intfId uint32, onuId uint32) []layers.DHCPOption {
86 hostname := []byte(fmt.Sprintf("%d.%d.%d.bbsim.onf.org", gemPortId, intfId, onuId))
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070087 opts := []layers.DHCPOption{}
88 opts = append(opts, layers.DHCPOption{
89 Type: layers.DHCPOptHostname,
90 Data: hostname,
91 Length: uint8(len(hostname)),
92 })
93
94 bytes := []byte{}
95 for _, option := range defaultParamsRequestList {
96 bytes = append(bytes, byte(option))
97 }
98
99 opts = append(opts, layers.DHCPOption{
100 Type: layers.DHCPOptParamsRequest,
101 Data: bytes,
102 Length: uint8(len(bytes)),
103 })
104 return opts
105}
106
Matteo Scandolo24a88c42020-09-17 14:55:28 -0700107func createDHCPDisc(intfId uint32, onuId uint32, gemPort uint32, macAddress net.HardwareAddr) *layers.DHCPv4 {
108 dhcpLayer := createDefaultDHCPReq(macAddress)
Matteo Scandolobfcfbb32020-09-28 14:14:39 -0700109 defaultOpts := createDefaultOpts(gemPort, intfId, onuId)
Shrey Baid688b4242020-07-10 20:40:10 +0530110 dhcpLayer.Options = append([]layers.DHCPOption{{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700111 Type: layers.DHCPOptMessageType,
112 Data: []byte{byte(layers.DHCPMsgTypeDiscover)},
113 Length: 1,
114 }}, defaultOpts...)
115
Matteo Scandolobfcfbb32020-09-28 14:14:39 -0700116 data := []byte{01}
117 data = append(data, macAddress...)
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700118 dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
119 Type: layers.DHCPOptClientID,
120 Data: data,
121 Length: uint8(len(data)),
122 })
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700123
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700124 return &dhcpLayer
125}
126
Matteo Scandolobfcfbb32020-09-28 14:14:39 -0700127func createDHCPReq(intfId uint32, onuId uint32, macAddress net.HardwareAddr, offeredIp net.IP, gemPortId uint32) *layers.DHCPv4 {
Matteo Scandolo24a88c42020-09-17 14:55:28 -0700128 dhcpLayer := createDefaultDHCPReq(macAddress)
Matteo Scandolobfcfbb32020-09-28 14:14:39 -0700129 defaultOpts := createDefaultOpts(gemPortId, intfId, onuId)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700130
131 dhcpLayer.Options = append(defaultOpts, layers.DHCPOption{
132 Type: layers.DHCPOptMessageType,
133 Data: []byte{byte(layers.DHCPMsgTypeRequest)},
134 Length: 1,
135 })
136
137 data := []byte{182, 21, 0, 128}
138 dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
139 Type: layers.DHCPOptServerID,
140 Data: data,
141 Length: uint8(len(data)),
142 })
143
144 data = []byte{0xcd, 0x28, 0xcb, 0xcc, 0x00, 0x01, 0x00, 0x01,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700145 0x23, 0xed, 0x11, 0xec, 0x4e, 0xfc, 0xcd, 0x28, byte(intfId), byte(onuId)}
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700146 dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
147 Type: layers.DHCPOptClientID,
148 Data: data,
149 Length: uint8(len(data)),
150 })
151
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700152 // NOTE we should not request a specific IP, or we should request the one that has been offered
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700153 dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
154 Type: layers.DHCPOptRequestIP,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700155 Data: offeredIp,
156 Length: uint8(len(offeredIp)),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700157 })
158 return &dhcpLayer
159}
160
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700161func serializeDHCPPacket(cTag int, srcMac net.HardwareAddr, dhcp *layers.DHCPv4, pbit uint8) (gopacket.Packet, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700162 buffer := gopacket.NewSerializeBuffer()
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800163
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700164 options := gopacket.SerializeOptions{
165 ComputeChecksums: true,
166 FixLengths: true,
167 }
168
169 ethernetLayer := &layers.Ethernet{
170 SrcMAC: srcMac,
171 DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
172 EthernetType: layers.EthernetTypeIPv4,
173 }
174
175 ipLayer := &layers.IPv4{
176 Version: 4,
177 TOS: 0x10,
178 TTL: 128,
179 SrcIP: []byte{0, 0, 0, 0},
180 DstIP: []byte{255, 255, 255, 255},
181 Protocol: layers.IPProtocolUDP,
182 }
183
184 udpLayer := &layers.UDP{
185 SrcPort: 68,
186 DstPort: 67,
187 }
188
Shrey Baid688b4242020-07-10 20:40:10 +0530189 _ = udpLayer.SetNetworkLayerForChecksum(ipLayer)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700190 if err := gopacket.SerializeLayers(buffer, options, ethernetLayer, ipLayer, udpLayer, dhcp); err != nil {
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800191 dhcpLogger.Error("SerializeLayers")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700192 return nil, err
193 }
194
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800195 untaggedPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeEthernet, gopacket.Default)
196
Matteo Scandolo8d281372020-09-03 16:23:37 -0700197 taggedPkt, err := packetHandlers.PushSingleTag(cTag, untaggedPkt, pbit)
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800198 if err != nil {
199 dhcpLogger.Error("TagPacket")
200 return nil, err
201 }
202
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700203 return taggedPkt, nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700204}
205
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700206func GetDhcpLayer(pkt gopacket.Packet) (*layers.DHCPv4, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700207 layerDHCP := pkt.Layer(layers.LayerTypeDHCPv4)
208 dhcp, _ := layerDHCP.(*layers.DHCPv4)
209 if dhcp == nil {
210 return nil, errors.New("Failed-to-extract-DHCP-layer")
211 }
212 return dhcp, nil
213}
214
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700215func GetDhcpMessageType(dhcp *layers.DHCPv4) (layers.DHCPMsgType, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700216 for _, option := range dhcp.Options {
217 if option.Type == layers.DHCPOptMessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700218 if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeDiscover)}) {
219 return layers.DHCPMsgTypeDiscover, nil
220 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeOffer)}) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700221 return layers.DHCPMsgTypeOffer, nil
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700222 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeRequest)}) {
223 return layers.DHCPMsgTypeRequest, nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700224 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeAck)}) {
225 return layers.DHCPMsgTypeAck, nil
226 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeRelease)}) {
227 return layers.DHCPMsgTypeRelease, nil
228 } else {
229 msg := fmt.Sprintf("This type %x is not supported", option.Data)
230 return 0, errors.New(msg)
231 }
232 }
233 }
234 return 0, errors.New("Failed to extract MsgType from dhcp")
235}
236
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700237// returns the DHCP Layer type or error if it's not a DHCP Packet
238func GetDhcpPacketType(pkt gopacket.Packet) (string, error) {
239 dhcpLayer, err := GetDhcpLayer(pkt)
240 if err != nil {
241 return "", err
242 }
243 dhcpMessageType, err := GetDhcpMessageType(dhcpLayer)
244 if err != nil {
245 return "", err
246 }
247
248 return dhcpMessageType.String(), nil
249}
250
Girish Gowdra62f24292021-05-12 16:28:39 -0700251func sendDHCPPktIn(msg bbsim.ByteMsg, portNo uint32, gemPortId uint32, uniId uint32, stream bbsim.Stream) error {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700252
Matteo Scandolo8d281372020-09-03 16:23:37 -0700253 dhcpLogger.WithFields(log.Fields{
Shrey Baid688b4242020-07-10 20:40:10 +0530254 "OnuId": msg.OnuId,
255 "IntfId": msg.IntfId,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700256 "GemPort": gemPortId,
Shrey Baid688b4242020-07-10 20:40:10 +0530257 "Type": "DHCP",
Matteo Scandolo8d281372020-09-03 16:23:37 -0700258 "Pkt": hex.EncodeToString(msg.Bytes),
259 }).Trace("Sending DHCP packet in")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700260
Matteo Scandolo8a574812021-05-20 15:18:53 -0700261 // TODO the adapter uses Onu, Uni and gemPort to route the packet,
262 // stop using PortNo to ensure consistent behavior
263 // requires voltha-protos:4.1.6
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700264 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
Matteo Scandolo27428702019-10-11 16:21:16 -0700265 IntfType: "pon",
266 IntfId: msg.IntfId,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700267 GemportId: gemPortId,
Matteo Scandolo27428702019-10-11 16:21:16 -0700268 Pkt: msg.Bytes,
269 PortNo: portNo,
Girish Gowdra62f24292021-05-12 16:28:39 -0700270 OnuId: msg.OnuId,
271 UniId: uniId,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700272 }}
273
274 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
275 dhcpLogger.Errorf("Fail to send DHCP PktInd indication. %v", err)
276 return err
277 }
278 return nil
279}
280
Matteo Scandolo24a88c42020-09-17 14:55:28 -0700281func sendDHCPRequest(ponPortId uint32, onuId uint32, serviceName string, serialNumber string, portNo uint32,
Matteo Scandolo8d281372020-09-03 16:23:37 -0700282 cTag int, gemPortId uint32, onuStateMachine *fsm.FSM, onuHwAddress net.HardwareAddr,
Girish Gowdra62f24292021-05-12 16:28:39 -0700283 offeredIp net.IP, pbit uint8, uniId uint32, stream bbsim.Stream) error {
Matteo Scandolobfcfbb32020-09-28 14:14:39 -0700284 dhcp := createDHCPReq(ponPortId, onuId, onuHwAddress, offeredIp, gemPortId)
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700285 pkt, err := serializeDHCPPacket(cTag, onuHwAddress, dhcp, pbit)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700286
287 if err != nil {
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700288 dhcpLogger.WithFields(log.Fields{
289 "OnuId": onuId,
290 "IntfId": ponPortId,
291 "OnuSn": serialNumber,
292 "OfferedIp": offeredIp.String(),
293 }).Errorf("Cannot serializeDHCPPacket: %s", err)
294 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
295 return err
296 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700297 return err
298 }
299 // NOTE I don't think we need to tag the packet
300 //taggedPkt, err := packetHandlers.PushSingleTag(cTag, pkt)
301
302 msg := bbsim.ByteMsg{
303 IntfId: ponPortId,
304 OnuId: onuId,
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700305 Bytes: pkt.Data(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700306 }
307
Girish Gowdra62f24292021-05-12 16:28:39 -0700308 if err := sendDHCPPktIn(msg, portNo, gemPortId, uniId, stream); err != nil {
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700309 dhcpLogger.WithFields(log.Fields{
310 "OnuId": onuId,
311 "IntfId": ponPortId,
312 "OnuSn": serialNumber,
313 }).Errorf("Cannot sendDHCPPktIn: %s", err)
314 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
315 return err
316 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700317 return err
318 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700319
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700320 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700321 "OnuId": onuId,
322 "IntfId": ponPortId,
323 "OnuSn": serialNumber,
324 "OfferedIp": offeredIp.String(),
325 "ServiceName": serviceName,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700326 }).Infof("DHCPRequest Sent")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700327 return nil
328}
329
Matteo Scandolo075b1892019-10-07 12:11:07 -0700330func updateDhcpFailed(onuId uint32, ponPortId uint32, serialNumber string, onuStateMachine *fsm.FSM) error {
331 if err := onuStateMachine.Event("dhcp_failed"); err != nil {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700332 dhcpLogger.WithFields(log.Fields{
333 "OnuId": onuId,
334 "IntfId": ponPortId,
335 "OnuSn": serialNumber,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700336 }).Errorf("Error while transitioning ONU State %v", err)
337 return err
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700338 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700339 return nil
340}
341
Matteo Scandolo24a88c42020-09-17 14:55:28 -0700342func SendDHCPDiscovery(ponPortId uint32, onuId uint32, serviceName string, cTag int, gemPortId uint32,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700343 serialNumber string, portNo uint32, uniId uint32, stateMachine *fsm.FSM, onuHwAddress net.HardwareAddr,
Matteo Scandolo8d281372020-09-03 16:23:37 -0700344 pbit uint8, stream bbsim.Stream) error {
345
Matteo Scandolo24a88c42020-09-17 14:55:28 -0700346 dhcp := createDHCPDisc(ponPortId, onuId, gemPortId, onuHwAddress)
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700347 pkt, err := serializeDHCPPacket(cTag, onuHwAddress, dhcp, pbit)
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800348
Matteo Scandolo075b1892019-10-07 12:11:07 -0700349 if err != nil {
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700350 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700351 "OnuId": onuId,
352 "IntfId": ponPortId,
353 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700354 "PortNo": portNo,
355 "UniId": uniId,
356 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700357 "ServiceName": serviceName,
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700358 }).Errorf("Cannot serializeDHCPPacket: %s", err)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700359 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, stateMachine); err != nil {
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700360 return err
361 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700362 return err
363 }
364 // NOTE I don't think we need to tag the packet
365 //taggedPkt, err := packetHandlers.PushSingleTag(cTag, pkt)
366
367 msg := bbsim.ByteMsg{
368 IntfId: ponPortId,
369 OnuId: onuId,
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700370 Bytes: pkt.Data(),
Matteo Scandolo075b1892019-10-07 12:11:07 -0700371 }
372
Girish Gowdra62f24292021-05-12 16:28:39 -0700373 if err := sendDHCPPktIn(msg, portNo, gemPortId, uniId, stream); err != nil {
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700374 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700375 "OnuId": onuId,
376 "IntfId": ponPortId,
377 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700378 "PortNo": portNo,
379 "UniId": uniId,
380 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700381 "ServiceName": serviceName,
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700382 }).Errorf("Cannot sendDHCPPktIn: %s", err)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700383 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, stateMachine); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700384 return err
385 }
386 return err
387 }
388 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700389 "OnuId": onuId,
390 "IntfId": ponPortId,
391 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700392 "PortNo": portNo,
393 "UniId": uniId,
394 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700395 "ServiceName": serviceName,
396 }).Info("DHCPDiscovery Sent")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700397
Matteo Scandolo4a036262020-08-17 15:56:13 -0700398 if err := stateMachine.Event("dhcp_discovery_sent"); err != nil {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700399 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700400 "OnuId": onuId,
401 "IntfId": ponPortId,
402 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700403 "PortNo": portNo,
404 "UniId": uniId,
405 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700406 "ServiceName": serviceName,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700407 }).Errorf("Error while transitioning ONU State %v", err)
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700408 return err
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700409 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700410 return nil
411}
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700412
Matteo Scandolo24a88c42020-09-17 14:55:28 -0700413func HandleNextPacket(onuId uint32, ponPortId uint32, serviceName string, serialNumber string, portNo uint32,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700414 cTag int, gemPortId uint32, uniId uint32, onuHwAddress net.HardwareAddr, onuStateMachine *fsm.FSM,
Matteo Scandolo8d281372020-09-03 16:23:37 -0700415 pkt gopacket.Packet, pbit uint8, stream bbsim.Stream) error {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700416
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700417 dhcpLayer, err := GetDhcpLayer(pkt)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700418 if err != nil {
419 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700420 "OnuId": onuId,
421 "IntfId": ponPortId,
422 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700423 "PortNo": portNo,
424 "UniId": uniId,
425 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700426 "ServiceName": serviceName,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700427 }).Errorf("Can't get DHCP Layer from Packet: %v", err)
428 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
429 return err
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700430 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700431 return err
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700432 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700433 dhcpMessageType, err := GetDhcpMessageType(dhcpLayer)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700434 if err != nil {
435 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700436 "OnuId": onuId,
437 "IntfId": ponPortId,
438 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700439 "PortNo": portNo,
440 "UniId": uniId,
441 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700442 "ServiceName": serviceName,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700443 }).Errorf("Can't get DHCP Message Type from DHCP Layer: %v", err)
444 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
445 return err
446 }
447 return err
448 }
449
450 if dhcpLayer.Operation == layers.DHCPOpReply {
451 if dhcpMessageType == layers.DHCPMsgTypeOffer {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700452 offeredIp := dhcpLayer.YourClientIP
Girish Gowdra62f24292021-05-12 16:28:39 -0700453 if err := sendDHCPRequest(ponPortId, onuId, serviceName, serialNumber, portNo, cTag, gemPortId, onuStateMachine, onuHwAddress, offeredIp, pbit, uniId, stream); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700454 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700455 "OnuId": onuId,
456 "IntfId": ponPortId,
457 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700458 "PortNo": portNo,
459 "UniId": uniId,
460 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700461 "ServiceName": serviceName,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700462 }).Errorf("Can't send DHCP Request: %s", err)
463 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
464 return err
465 }
466 return err
467 }
468 if err := onuStateMachine.Event("dhcp_request_sent"); err != nil {
469 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700470 "OnuId": onuId,
471 "IntfId": ponPortId,
472 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700473 "PortNo": portNo,
474 "UniId": uniId,
475 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700476 "ServiceName": serviceName,
477 }).Errorf("Error while transitioning State %v", err)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700478 }
479
480 } else if dhcpMessageType == layers.DHCPMsgTypeAck {
481 // NOTE once the ack is received we don't need to do anything but change the state
482 if err := onuStateMachine.Event("dhcp_ack_received"); err != nil {
483 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700484 "OnuId": onuId,
485 "IntfId": ponPortId,
486 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700487 "PortNo": portNo,
488 "UniId": uniId,
489 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700490 "ServiceName": serviceName,
491 }).Errorf("Error while transitioning State %v", err)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700492 }
493 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700494 "OnuId": onuId,
495 "IntfId": ponPortId,
496 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700497 "PortNo": portNo,
498 "UniId": uniId,
499 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700500 "ServiceName": serviceName,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700501 }).Infof("DHCP State machine completed")
502 }
503 // NOTE do we need to care about DHCPMsgTypeRelease??
504 } else {
505 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700506 "OnuId": onuId,
507 "IntfId": ponPortId,
508 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700509 "PortNo": portNo,
510 "UniId": uniId,
511 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700512 "ServiceName": serviceName,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700513 }).Warnf("Unsupported DHCP Operation: %s", dhcpLayer.Operation.String())
514 }
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700515
Matteo Scandolo075b1892019-10-07 12:11:07 -0700516 return nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700517}
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700518
519// This method handle the BBR DHCP Packets
520// BBR does not need to do anything but forward the packets in the correct direction
Matteo Scandolo4a036262020-08-17 15:56:13 -0700521func HandleNextBbrPacket(onuId uint32, ponPortId uint32, serialNumber string, doneChannel chan bool, pkt gopacket.Packet, client openolt.OpenoltClient) error {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700522
523 // check if the packet is going:
524 // - outgouing: toward the DHCP
525 // - incoming: toward the ONU
526 isIncoming := packetHandlers.IsIncomingPacket(pkt)
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800527 dhcpLogger.Tracef("Is Incoming: %t", isIncoming)
528
529 pkt, err := packetHandlers.PopSingleTag(pkt)
530 if err != nil {
531 dhcpLogger.WithFields(log.Fields{
532 "OnuId": onuId,
533 "IntfId": ponPortId,
534 "OnuSn": serialNumber,
535 "error": err,
536 }).Fatalf("Can't untag packet")
537 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700538
539 dhcpType, err := GetDhcpPacketType(pkt)
540 if err != nil {
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800541 dhcpLogger.WithFields(log.Fields{
542 "OnuId": onuId,
543 "IntfId": ponPortId,
544 "OnuSn": serialNumber,
545 "error": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700546 }).Fatalf("Can't find DHCP type for packet")
547 }
548
549 srcMac, _ := packetHandlers.GetSrcMacAddressFromPacket(pkt)
550 dstMac, _ := packetHandlers.GetDstMacAddressFromPacket(pkt)
551
Shrey Baid688b4242020-07-10 20:40:10 +0530552 if isIncoming {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700553
554 onuPacket := openolt.OnuPacket{
555 IntfId: ponPortId,
556 OnuId: onuId,
557 PortNo: onuId,
558 GemportId: 1,
559 Pkt: pkt.Data(),
560 }
561
562 if _, err := client.OnuPacketOut(context.Background(), &onuPacket); err != nil {
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800563 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700564 "OnuId": onuId,
565 "IntfId": ponPortId,
566 "OnuSn": serialNumber,
567 "Type": dhcpType,
568 "error": err,
569 }).Error("Failed to send DHCP packet to the ONU")
570 }
571
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800572 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700573 "OnuId": onuId,
574 "IntfId": ponPortId,
575 "OnuSn": serialNumber,
576 "Type": dhcpType,
577 "DstMac": dstMac,
578 "SrcMac": srcMac,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700579 }).Infof("Sent DHCP packet to the ONU")
580
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700581 dhcpLayer, _ := GetDhcpLayer(pkt)
582 dhcpMessageType, _ := GetDhcpMessageType(dhcpLayer)
583 if dhcpMessageType == layers.DHCPMsgTypeAck {
584 doneChannel <- true
585 }
586
587 } else {
588 // double tag the packet and send it to the NNI
Matteo Scandolo4a036262020-08-17 15:56:13 -0700589 // we don't really care about the tags as they are stripped before
590 // the packet is sent to the DHCP server
Matteo Scandolo8d281372020-09-03 16:23:37 -0700591 // in BBR we don't care about the pBit
592 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(900, 900, pkt, 0)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700593 if err != nil {
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800594 dhcpLogger.WithFields(log.Fields{
595 "OnuId": onuId,
596 "IntfId": ponPortId,
597 "OnuSn": serialNumber,
598 "Type": dhcpType,
599 "error": err,
600 }).Error("Failed to add double tag to packet")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700601 }
602
603 pkt := openolt.UplinkPacket{
604 IntfId: 0, // BBSim does not care about which NNI, it has only one
605 Pkt: doubleTaggedPkt.Data(),
606 }
607 if _, err := client.UplinkPacketOut(context.Background(), &pkt); err != nil {
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800608 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700609 "OnuId": onuId,
610 "IntfId": ponPortId,
611 "OnuSn": serialNumber,
612 "Type": dhcpType,
613 "error": err,
614 }).Error("Failed to send DHCP packet out of the NNI Port")
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700615 return err
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700616 }
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800617 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700618 "OnuId": onuId,
619 "IntfId": ponPortId,
620 "OnuSn": serialNumber,
621 "Type": dhcpType,
622 "DstMac": dstMac,
623 "SrcMac": srcMac,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700624 }).Infof("Sent DHCP packet out of the NNI Port")
625 }
626 return nil
627}