blob: 7fc7b3c40886f3cf29b087a487026f3263742f64 [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"
Elia Battistona9666542022-03-17 15:45:45 +010024 "net"
25 "reflect"
26 "strconv"
27
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070028 "github.com/google/gopacket"
29 "github.com/google/gopacket/layers"
30 "github.com/looplab/fsm"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070031 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070032 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
David K. Bainbridgec415efe2021-08-19 13:05:21 +000033 "github.com/opencord/voltha-protos/v5/go/openolt"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070034 log "github.com/sirupsen/logrus"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070035)
36
37var dhcpLogger = log.WithFields(log.Fields{
38 "module": "DHCP",
39})
40
41var defaultParamsRequestList = []layers.DHCPOpt{
42 layers.DHCPOptSubnetMask,
43 layers.DHCPOptBroadcastAddr,
44 layers.DHCPOptTimeOffset,
45 layers.DHCPOptRouter,
46 layers.DHCPOptDomainName,
47 layers.DHCPOptDNS,
48 layers.DHCPOptDomainSearch,
49 layers.DHCPOptHostname,
50 layers.DHCPOptNetBIOSTCPNS,
51 layers.DHCPOptNetBIOSTCPScope,
52 layers.DHCPOptInterfaceMTU,
53 layers.DHCPOptClasslessStaticRoute,
54 layers.DHCPOptNTPServers,
55}
56
Matteo Scandolo24a88c42020-09-17 14:55:28 -070057func macAddressToTxId(mac net.HardwareAddr) uint32 {
58
59 // NOTE we want to generate a unique XID,
60 // the easiest way is to transform the macAddress (already unique) into an integer
61 str := ""
62 for _, i := range mac {
63 str = str + fmt.Sprintf("%d", i)
64 }
65 xid, err := strconv.Atoi(str)
Matteo Scandolofe9ac252019-10-25 11:40:17 -070066 if err != nil {
67 log.Fatal("Can't generate unique XID for ONU")
68 }
69
Matteo Scandolo24a88c42020-09-17 14:55:28 -070070 return uint32(xid)
71}
72
73func createDefaultDHCPReq(mac net.HardwareAddr) layers.DHCPv4 {
74 xid := macAddressToTxId(mac)
75
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070076 return layers.DHCPv4{
77 Operation: layers.DHCPOpRequest,
78 HardwareType: layers.LinkTypeEthernet,
79 HardwareLen: 6,
80 HardwareOpts: 0,
Matteo Scandolofe9ac252019-10-25 11:40:17 -070081 Xid: uint32(xid),
Matteo Scandolo40e067f2019-10-16 16:59:41 -070082 ClientHWAddr: mac,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070083 }
84}
85
Matteo Scandolobfcfbb32020-09-28 14:14:39 -070086func createDefaultOpts(gemPortId uint32, intfId uint32, onuId uint32) []layers.DHCPOption {
87 hostname := []byte(fmt.Sprintf("%d.%d.%d.bbsim.onf.org", gemPortId, intfId, onuId))
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070088 opts := []layers.DHCPOption{}
89 opts = append(opts, layers.DHCPOption{
90 Type: layers.DHCPOptHostname,
91 Data: hostname,
92 Length: uint8(len(hostname)),
93 })
94
95 bytes := []byte{}
96 for _, option := range defaultParamsRequestList {
97 bytes = append(bytes, byte(option))
98 }
99
100 opts = append(opts, layers.DHCPOption{
101 Type: layers.DHCPOptParamsRequest,
102 Data: bytes,
103 Length: uint8(len(bytes)),
104 })
105 return opts
106}
107
Matteo Scandolo24a88c42020-09-17 14:55:28 -0700108func createDHCPDisc(intfId uint32, onuId uint32, gemPort uint32, macAddress net.HardwareAddr) *layers.DHCPv4 {
109 dhcpLayer := createDefaultDHCPReq(macAddress)
Matteo Scandolobfcfbb32020-09-28 14:14:39 -0700110 defaultOpts := createDefaultOpts(gemPort, intfId, onuId)
Shrey Baid688b4242020-07-10 20:40:10 +0530111 dhcpLayer.Options = append([]layers.DHCPOption{{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700112 Type: layers.DHCPOptMessageType,
113 Data: []byte{byte(layers.DHCPMsgTypeDiscover)},
114 Length: 1,
115 }}, defaultOpts...)
116
Matteo Scandolobfcfbb32020-09-28 14:14:39 -0700117 data := []byte{01}
118 data = append(data, macAddress...)
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700119 dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
120 Type: layers.DHCPOptClientID,
121 Data: data,
122 Length: uint8(len(data)),
123 })
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700124
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700125 return &dhcpLayer
126}
127
Matteo Scandolobfcfbb32020-09-28 14:14:39 -0700128func createDHCPReq(intfId uint32, onuId uint32, macAddress net.HardwareAddr, offeredIp net.IP, gemPortId uint32) *layers.DHCPv4 {
Matteo Scandolo24a88c42020-09-17 14:55:28 -0700129 dhcpLayer := createDefaultDHCPReq(macAddress)
Matteo Scandolobfcfbb32020-09-28 14:14:39 -0700130 defaultOpts := createDefaultOpts(gemPortId, intfId, onuId)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700131
132 dhcpLayer.Options = append(defaultOpts, layers.DHCPOption{
133 Type: layers.DHCPOptMessageType,
134 Data: []byte{byte(layers.DHCPMsgTypeRequest)},
135 Length: 1,
136 })
137
138 data := []byte{182, 21, 0, 128}
139 dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
140 Type: layers.DHCPOptServerID,
141 Data: data,
142 Length: uint8(len(data)),
143 })
144
145 data = []byte{0xcd, 0x28, 0xcb, 0xcc, 0x00, 0x01, 0x00, 0x01,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700146 0x23, 0xed, 0x11, 0xec, 0x4e, 0xfc, 0xcd, 0x28, byte(intfId), byte(onuId)}
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700147 dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
148 Type: layers.DHCPOptClientID,
149 Data: data,
150 Length: uint8(len(data)),
151 })
152
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700153 // 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 -0700154 dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
155 Type: layers.DHCPOptRequestIP,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700156 Data: offeredIp,
157 Length: uint8(len(offeredIp)),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700158 })
159 return &dhcpLayer
160}
161
Elia Battistona9666542022-03-17 15:45:45 +0100162func serializeDHCPPacket(tag int, srcMac net.HardwareAddr, dhcp *layers.DHCPv4, pbit uint8) (gopacket.Packet, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700163 buffer := gopacket.NewSerializeBuffer()
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800164
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700165 options := gopacket.SerializeOptions{
166 ComputeChecksums: true,
167 FixLengths: true,
168 }
169
170 ethernetLayer := &layers.Ethernet{
171 SrcMAC: srcMac,
172 DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
173 EthernetType: layers.EthernetTypeIPv4,
174 }
175
176 ipLayer := &layers.IPv4{
177 Version: 4,
178 TOS: 0x10,
179 TTL: 128,
180 SrcIP: []byte{0, 0, 0, 0},
181 DstIP: []byte{255, 255, 255, 255},
182 Protocol: layers.IPProtocolUDP,
183 }
184
185 udpLayer := &layers.UDP{
186 SrcPort: 68,
187 DstPort: 67,
188 }
189
Shrey Baid688b4242020-07-10 20:40:10 +0530190 _ = udpLayer.SetNetworkLayerForChecksum(ipLayer)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700191 if err := gopacket.SerializeLayers(buffer, options, ethernetLayer, ipLayer, udpLayer, dhcp); err != nil {
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800192 dhcpLogger.Error("SerializeLayers")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700193 return nil, err
194 }
195
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800196 untaggedPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeEthernet, gopacket.Default)
197
Elia Battistona9666542022-03-17 15:45:45 +0100198 taggedPkt, err := packetHandlers.PushSingleTag(tag, untaggedPkt, pbit)
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800199 if err != nil {
200 dhcpLogger.Error("TagPacket")
201 return nil, err
202 }
203
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700204 return taggedPkt, nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700205}
206
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700207func GetDhcpLayer(pkt gopacket.Packet) (*layers.DHCPv4, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700208 layerDHCP := pkt.Layer(layers.LayerTypeDHCPv4)
209 dhcp, _ := layerDHCP.(*layers.DHCPv4)
210 if dhcp == nil {
211 return nil, errors.New("Failed-to-extract-DHCP-layer")
212 }
213 return dhcp, nil
214}
215
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700216func GetDhcpMessageType(dhcp *layers.DHCPv4) (layers.DHCPMsgType, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700217 for _, option := range dhcp.Options {
218 if option.Type == layers.DHCPOptMessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700219 if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeDiscover)}) {
220 return layers.DHCPMsgTypeDiscover, nil
221 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeOffer)}) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700222 return layers.DHCPMsgTypeOffer, nil
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700223 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeRequest)}) {
224 return layers.DHCPMsgTypeRequest, nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700225 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeAck)}) {
226 return layers.DHCPMsgTypeAck, nil
227 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeRelease)}) {
228 return layers.DHCPMsgTypeRelease, nil
229 } else {
230 msg := fmt.Sprintf("This type %x is not supported", option.Data)
231 return 0, errors.New(msg)
232 }
233 }
234 }
235 return 0, errors.New("Failed to extract MsgType from dhcp")
236}
237
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700238// returns the DHCP Layer type or error if it's not a DHCP Packet
239func GetDhcpPacketType(pkt gopacket.Packet) (string, error) {
240 dhcpLayer, err := GetDhcpLayer(pkt)
241 if err != nil {
242 return "", err
243 }
244 dhcpMessageType, err := GetDhcpMessageType(dhcpLayer)
245 if err != nil {
246 return "", err
247 }
248
249 return dhcpMessageType.String(), nil
250}
251
Girish Gowdra62f24292021-05-12 16:28:39 -0700252func sendDHCPPktIn(msg bbsim.ByteMsg, portNo uint32, gemPortId uint32, uniId uint32, stream bbsim.Stream) error {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700253
Matteo Scandolo8d281372020-09-03 16:23:37 -0700254 dhcpLogger.WithFields(log.Fields{
Shrey Baid688b4242020-07-10 20:40:10 +0530255 "OnuId": msg.OnuId,
256 "IntfId": msg.IntfId,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700257 "GemPort": gemPortId,
Shrey Baid688b4242020-07-10 20:40:10 +0530258 "Type": "DHCP",
Matteo Scandolo8d281372020-09-03 16:23:37 -0700259 "Pkt": hex.EncodeToString(msg.Bytes),
260 }).Trace("Sending DHCP packet in")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700261
Matteo Scandolo8a574812021-05-20 15:18:53 -0700262 // TODO the adapter uses Onu, Uni and gemPort to route the packet,
263 // stop using PortNo to ensure consistent behavior
264 // requires voltha-protos:4.1.6
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700265 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
Matteo Scandolo27428702019-10-11 16:21:16 -0700266 IntfType: "pon",
267 IntfId: msg.IntfId,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700268 GemportId: gemPortId,
Matteo Scandolo27428702019-10-11 16:21:16 -0700269 Pkt: msg.Bytes,
270 PortNo: portNo,
Girish Gowdra62f24292021-05-12 16:28:39 -0700271 OnuId: msg.OnuId,
272 UniId: uniId,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700273 }}
274
275 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
276 dhcpLogger.Errorf("Fail to send DHCP PktInd indication. %v", err)
277 return err
278 }
279 return nil
280}
281
Matteo Scandolo24a88c42020-09-17 14:55:28 -0700282func sendDHCPRequest(ponPortId uint32, onuId uint32, serviceName string, serialNumber string, portNo uint32,
Elia Battistona9666542022-03-17 15:45:45 +0100283 tag int, gemPortId uint32, onuStateMachine *fsm.FSM, onuHwAddress net.HardwareAddr,
Girish Gowdra62f24292021-05-12 16:28:39 -0700284 offeredIp net.IP, pbit uint8, uniId uint32, stream bbsim.Stream) error {
Matteo Scandolobfcfbb32020-09-28 14:14:39 -0700285 dhcp := createDHCPReq(ponPortId, onuId, onuHwAddress, offeredIp, gemPortId)
Elia Battistona9666542022-03-17 15:45:45 +0100286 pkt, err := serializeDHCPPacket(tag, onuHwAddress, dhcp, pbit)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700287
288 if err != nil {
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700289 dhcpLogger.WithFields(log.Fields{
290 "OnuId": onuId,
291 "IntfId": ponPortId,
292 "OnuSn": serialNumber,
293 "OfferedIp": offeredIp.String(),
294 }).Errorf("Cannot serializeDHCPPacket: %s", err)
295 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
296 return err
297 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700298 return err
299 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700300
301 msg := bbsim.ByteMsg{
302 IntfId: ponPortId,
303 OnuId: onuId,
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700304 Bytes: pkt.Data(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700305 }
306
Girish Gowdra62f24292021-05-12 16:28:39 -0700307 if err := sendDHCPPktIn(msg, portNo, gemPortId, uniId, stream); err != nil {
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700308 dhcpLogger.WithFields(log.Fields{
309 "OnuId": onuId,
310 "IntfId": ponPortId,
311 "OnuSn": serialNumber,
312 }).Errorf("Cannot sendDHCPPktIn: %s", err)
313 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
314 return err
315 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700316 return err
317 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700318
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700319 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700320 "OnuId": onuId,
321 "IntfId": ponPortId,
322 "OnuSn": serialNumber,
323 "OfferedIp": offeredIp.String(),
324 "ServiceName": serviceName,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700325 }).Infof("DHCPRequest Sent")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700326 return nil
327}
328
Matteo Scandolo075b1892019-10-07 12:11:07 -0700329func updateDhcpFailed(onuId uint32, ponPortId uint32, serialNumber string, onuStateMachine *fsm.FSM) error {
330 if err := onuStateMachine.Event("dhcp_failed"); err != nil {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700331 dhcpLogger.WithFields(log.Fields{
332 "OnuId": onuId,
333 "IntfId": ponPortId,
334 "OnuSn": serialNumber,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700335 }).Errorf("Error while transitioning ONU State %v", err)
336 return err
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700337 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700338 return nil
339}
340
Elia Battistona9666542022-03-17 15:45:45 +0100341func SendDHCPDiscovery(ponPortId uint32, onuId uint32, serviceName string, tag int, gemPortId uint32,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700342 serialNumber string, portNo uint32, uniId uint32, stateMachine *fsm.FSM, onuHwAddress net.HardwareAddr,
Matteo Scandolo8d281372020-09-03 16:23:37 -0700343 pbit uint8, stream bbsim.Stream) error {
344
Matteo Scandolo24a88c42020-09-17 14:55:28 -0700345 dhcp := createDHCPDisc(ponPortId, onuId, gemPortId, onuHwAddress)
Elia Battistona9666542022-03-17 15:45:45 +0100346 pkt, err := serializeDHCPPacket(tag, onuHwAddress, dhcp, pbit)
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800347
Matteo Scandolo075b1892019-10-07 12:11:07 -0700348 if err != nil {
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700349 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700350 "OnuId": onuId,
351 "IntfId": ponPortId,
352 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700353 "PortNo": portNo,
354 "UniId": uniId,
355 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700356 "ServiceName": serviceName,
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700357 }).Errorf("Cannot serializeDHCPPacket: %s", err)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700358 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, stateMachine); err != nil {
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700359 return err
360 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700361 return err
362 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700363
364 msg := bbsim.ByteMsg{
365 IntfId: ponPortId,
366 OnuId: onuId,
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700367 Bytes: pkt.Data(),
Matteo Scandolo075b1892019-10-07 12:11:07 -0700368 }
369
Girish Gowdra62f24292021-05-12 16:28:39 -0700370 if err := sendDHCPPktIn(msg, portNo, gemPortId, uniId, stream); err != nil {
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700371 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700372 "OnuId": onuId,
373 "IntfId": ponPortId,
374 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700375 "PortNo": portNo,
376 "UniId": uniId,
377 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700378 "ServiceName": serviceName,
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700379 }).Errorf("Cannot sendDHCPPktIn: %s", err)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700380 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, stateMachine); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700381 return err
382 }
383 return err
384 }
385 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700386 "OnuId": onuId,
387 "IntfId": ponPortId,
388 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700389 "PortNo": portNo,
390 "UniId": uniId,
391 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700392 "ServiceName": serviceName,
393 }).Info("DHCPDiscovery Sent")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700394
Matteo Scandolo4a036262020-08-17 15:56:13 -0700395 if err := stateMachine.Event("dhcp_discovery_sent"); err != nil {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700396 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700397 "OnuId": onuId,
398 "IntfId": ponPortId,
399 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700400 "PortNo": portNo,
401 "UniId": uniId,
402 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700403 "ServiceName": serviceName,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700404 }).Errorf("Error while transitioning ONU State %v", err)
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700405 return err
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700406 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700407 return nil
408}
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700409
Matteo Scandolo24a88c42020-09-17 14:55:28 -0700410func HandleNextPacket(onuId uint32, ponPortId uint32, serviceName string, serialNumber string, portNo uint32,
Elia Battistona9666542022-03-17 15:45:45 +0100411 tag int, gemPortId uint32, uniId uint32, onuHwAddress net.HardwareAddr, onuStateMachine *fsm.FSM,
Matteo Scandolo8d281372020-09-03 16:23:37 -0700412 pkt gopacket.Packet, pbit uint8, stream bbsim.Stream) error {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700413
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700414 dhcpLayer, err := GetDhcpLayer(pkt)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700415 if err != nil {
416 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700417 "OnuId": onuId,
418 "IntfId": ponPortId,
419 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700420 "PortNo": portNo,
421 "UniId": uniId,
422 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700423 "ServiceName": serviceName,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700424 }).Errorf("Can't get DHCP Layer from Packet: %v", err)
425 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
426 return err
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700427 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700428 return err
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700429 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700430 dhcpMessageType, err := GetDhcpMessageType(dhcpLayer)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700431 if err != nil {
432 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700433 "OnuId": onuId,
434 "IntfId": ponPortId,
435 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700436 "PortNo": portNo,
437 "UniId": uniId,
438 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700439 "ServiceName": serviceName,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700440 }).Errorf("Can't get DHCP Message Type from DHCP Layer: %v", err)
441 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
442 return err
443 }
444 return err
445 }
446
447 if dhcpLayer.Operation == layers.DHCPOpReply {
448 if dhcpMessageType == layers.DHCPMsgTypeOffer {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700449 offeredIp := dhcpLayer.YourClientIP
Elia Battistona9666542022-03-17 15:45:45 +0100450 if err := sendDHCPRequest(ponPortId, onuId, serviceName, serialNumber, portNo, tag, gemPortId, onuStateMachine, onuHwAddress, offeredIp, pbit, uniId, stream); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700451 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700452 "OnuId": onuId,
453 "IntfId": ponPortId,
454 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700455 "PortNo": portNo,
456 "UniId": uniId,
457 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700458 "ServiceName": serviceName,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700459 }).Errorf("Can't send DHCP Request: %s", err)
460 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
461 return err
462 }
463 return err
464 }
465 if err := onuStateMachine.Event("dhcp_request_sent"); err != nil {
466 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700467 "OnuId": onuId,
468 "IntfId": ponPortId,
469 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700470 "PortNo": portNo,
471 "UniId": uniId,
472 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700473 "ServiceName": serviceName,
474 }).Errorf("Error while transitioning State %v", err)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700475 }
476
477 } else if dhcpMessageType == layers.DHCPMsgTypeAck {
478 // NOTE once the ack is received we don't need to do anything but change the state
479 if err := onuStateMachine.Event("dhcp_ack_received"); err != nil {
480 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700481 "OnuId": onuId,
482 "IntfId": ponPortId,
483 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700484 "PortNo": portNo,
485 "UniId": uniId,
486 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700487 "ServiceName": serviceName,
488 }).Errorf("Error while transitioning State %v", err)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700489 }
490 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700491 "OnuId": onuId,
492 "IntfId": ponPortId,
493 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700494 "PortNo": portNo,
495 "UniId": uniId,
496 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700497 "ServiceName": serviceName,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700498 }).Infof("DHCP State machine completed")
499 }
500 // NOTE do we need to care about DHCPMsgTypeRelease??
501 } else {
502 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700503 "OnuId": onuId,
504 "IntfId": ponPortId,
505 "OnuSn": serialNumber,
Matteo Scandolo8a574812021-05-20 15:18:53 -0700506 "PortNo": portNo,
507 "UniId": uniId,
508 "GemPortId": gemPortId,
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700509 "ServiceName": serviceName,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700510 }).Warnf("Unsupported DHCP Operation: %s", dhcpLayer.Operation.String())
511 }
Matteo Scandolofe9ac252019-10-25 11:40:17 -0700512
Matteo Scandolo075b1892019-10-07 12:11:07 -0700513 return nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700514}
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700515
516// This method handle the BBR DHCP Packets
517// BBR does not need to do anything but forward the packets in the correct direction
Matteo Scandolo4a036262020-08-17 15:56:13 -0700518func HandleNextBbrPacket(onuId uint32, ponPortId uint32, serialNumber string, doneChannel chan bool, pkt gopacket.Packet, client openolt.OpenoltClient) error {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700519
520 // check if the packet is going:
521 // - outgouing: toward the DHCP
522 // - incoming: toward the ONU
523 isIncoming := packetHandlers.IsIncomingPacket(pkt)
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800524 dhcpLogger.Tracef("Is Incoming: %t", isIncoming)
525
526 pkt, err := packetHandlers.PopSingleTag(pkt)
527 if err != nil {
528 dhcpLogger.WithFields(log.Fields{
529 "OnuId": onuId,
530 "IntfId": ponPortId,
531 "OnuSn": serialNumber,
532 "error": err,
533 }).Fatalf("Can't untag packet")
534 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700535
536 dhcpType, err := GetDhcpPacketType(pkt)
537 if err != nil {
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800538 dhcpLogger.WithFields(log.Fields{
539 "OnuId": onuId,
540 "IntfId": ponPortId,
541 "OnuSn": serialNumber,
542 "error": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700543 }).Fatalf("Can't find DHCP type for packet")
544 }
545
546 srcMac, _ := packetHandlers.GetSrcMacAddressFromPacket(pkt)
547 dstMac, _ := packetHandlers.GetDstMacAddressFromPacket(pkt)
548
Shrey Baid688b4242020-07-10 20:40:10 +0530549 if isIncoming {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700550
551 onuPacket := openolt.OnuPacket{
552 IntfId: ponPortId,
553 OnuId: onuId,
554 PortNo: onuId,
555 GemportId: 1,
556 Pkt: pkt.Data(),
557 }
558
559 if _, err := client.OnuPacketOut(context.Background(), &onuPacket); err != nil {
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800560 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700561 "OnuId": onuId,
562 "IntfId": ponPortId,
563 "OnuSn": serialNumber,
564 "Type": dhcpType,
565 "error": err,
566 }).Error("Failed to send DHCP packet to the ONU")
567 }
568
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800569 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700570 "OnuId": onuId,
571 "IntfId": ponPortId,
572 "OnuSn": serialNumber,
573 "Type": dhcpType,
574 "DstMac": dstMac,
575 "SrcMac": srcMac,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700576 }).Infof("Sent DHCP packet to the ONU")
577
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700578 dhcpLayer, _ := GetDhcpLayer(pkt)
579 dhcpMessageType, _ := GetDhcpMessageType(dhcpLayer)
580 if dhcpMessageType == layers.DHCPMsgTypeAck {
581 doneChannel <- true
582 }
583
584 } else {
585 // double tag the packet and send it to the NNI
Matteo Scandolo4a036262020-08-17 15:56:13 -0700586 // we don't really care about the tags as they are stripped before
587 // the packet is sent to the DHCP server
Matteo Scandolo8d281372020-09-03 16:23:37 -0700588 // in BBR we don't care about the pBit
589 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(900, 900, pkt, 0)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700590 if err != nil {
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800591 dhcpLogger.WithFields(log.Fields{
592 "OnuId": onuId,
593 "IntfId": ponPortId,
594 "OnuSn": serialNumber,
595 "Type": dhcpType,
596 "error": err,
597 }).Error("Failed to add double tag to packet")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700598 }
599
600 pkt := openolt.UplinkPacket{
601 IntfId: 0, // BBSim does not care about which NNI, it has only one
602 Pkt: doubleTaggedPkt.Data(),
603 }
604 if _, err := client.UplinkPacketOut(context.Background(), &pkt); err != nil {
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800605 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700606 "OnuId": onuId,
607 "IntfId": ponPortId,
608 "OnuSn": serialNumber,
609 "Type": dhcpType,
610 "error": err,
611 }).Error("Failed to send DHCP packet out of the NNI Port")
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700612 return err
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700613 }
Matteo Scandoloe0e9b772020-02-03 14:23:43 -0800614 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700615 "OnuId": onuId,
616 "IntfId": ponPortId,
617 "OnuSn": serialNumber,
618 "Type": dhcpType,
619 "DstMac": dstMac,
620 "SrcMac": srcMac,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700621 }).Infof("Sent DHCP packet out of the NNI Port")
622 }
623 return nil
624}