blob: 25f5210c21e69b4463f6a1a31f75be566e10de5f [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 Scandolo4b3fc7e2019-09-17 16:49:54 -070021 "errors"
22 "fmt"
23 "github.com/google/gopacket"
24 "github.com/google/gopacket/layers"
25 "github.com/looplab/fsm"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070026 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070027 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
28 omci "github.com/opencord/omci-sim"
29 "github.com/opencord/voltha-protos/go/openolt"
30 log "github.com/sirupsen/logrus"
31 "net"
32 "reflect"
33)
34
Matteo Scandolo075b1892019-10-07 12:11:07 -070035var GetGemPortId = omci.GetGemPortId
36
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070037var 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 Scandolo40e067f2019-10-16 16:59:41 -070057func createDefaultDHCPReq(intfId uint32, onuId uint32, mac net.HardwareAddr) layers.DHCPv4 {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070058 return layers.DHCPv4{
59 Operation: layers.DHCPOpRequest,
60 HardwareType: layers.LinkTypeEthernet,
61 HardwareLen: 6,
62 HardwareOpts: 0,
63 Xid: onuId,
Matteo Scandolo40e067f2019-10-16 16:59:41 -070064 ClientHWAddr: mac,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070065 }
66}
67
68func createDefaultOpts() []layers.DHCPOption {
69 hostname := []byte("bbsim.onf.org")
70 opts := []layers.DHCPOption{}
71 opts = append(opts, layers.DHCPOption{
72 Type: layers.DHCPOptHostname,
73 Data: hostname,
74 Length: uint8(len(hostname)),
75 })
76
77 bytes := []byte{}
78 for _, option := range defaultParamsRequestList {
79 bytes = append(bytes, byte(option))
80 }
81
82 opts = append(opts, layers.DHCPOption{
83 Type: layers.DHCPOptParamsRequest,
84 Data: bytes,
85 Length: uint8(len(bytes)),
86 })
87 return opts
88}
89
Matteo Scandolo40e067f2019-10-16 16:59:41 -070090func createDHCPDisc(intfId uint32, onuId uint32, macAddress net.HardwareAddr) *layers.DHCPv4 {
91 dhcpLayer := createDefaultDHCPReq(intfId, onuId, macAddress)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070092 defaultOpts := createDefaultOpts()
93 dhcpLayer.Options = append([]layers.DHCPOption{layers.DHCPOption{
94 Type: layers.DHCPOptMessageType,
95 Data: []byte{byte(layers.DHCPMsgTypeDiscover)},
96 Length: 1,
97 }}, defaultOpts...)
98
Matteo Scandolo40e067f2019-10-16 16:59:41 -070099 //data := []byte{0xcd, 0x28, 0xcb, 0xcc, 0x00, 0x01, 0x00, 0x01,
100 // 0x23, 0xed, 0x11, 0xec, 0x4e, 0xfc, 0xcd, 0x28, byte(intfId), byte(onuId)}
101 //dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
102 // Type: layers.DHCPOptClientID,
103 // Data: data,
104 // Length: uint8(len(data)),
105 //})
106
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700107 return &dhcpLayer
108}
109
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700110func createDHCPReq(intfId uint32, onuId uint32, macAddress net.HardwareAddr, offeredIp net.IP) *layers.DHCPv4 {
111 dhcpLayer := createDefaultDHCPReq(intfId, onuId, macAddress)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700112 defaultOpts := createDefaultOpts()
113
114 dhcpLayer.Options = append(defaultOpts, layers.DHCPOption{
115 Type: layers.DHCPOptMessageType,
116 Data: []byte{byte(layers.DHCPMsgTypeRequest)},
117 Length: 1,
118 })
119
120 data := []byte{182, 21, 0, 128}
121 dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
122 Type: layers.DHCPOptServerID,
123 Data: data,
124 Length: uint8(len(data)),
125 })
126
127 data = []byte{0xcd, 0x28, 0xcb, 0xcc, 0x00, 0x01, 0x00, 0x01,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700128 0x23, 0xed, 0x11, 0xec, 0x4e, 0xfc, 0xcd, 0x28, byte(intfId), byte(onuId)}
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700129 dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
130 Type: layers.DHCPOptClientID,
131 Data: data,
132 Length: uint8(len(data)),
133 })
134
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700135 // 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 -0700136 dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
137 Type: layers.DHCPOptRequestIP,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700138 Data: offeredIp,
139 Length: uint8(len(offeredIp)),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700140 })
141 return &dhcpLayer
142}
143
144func serializeDHCPPacket(intfId uint32, onuId uint32, srcMac net.HardwareAddr, dhcp *layers.DHCPv4) ([]byte, error) {
145 buffer := gopacket.NewSerializeBuffer()
146 options := gopacket.SerializeOptions{
147 ComputeChecksums: true,
148 FixLengths: true,
149 }
150
151 ethernetLayer := &layers.Ethernet{
152 SrcMAC: srcMac,
153 DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
154 EthernetType: layers.EthernetTypeIPv4,
155 }
156
157 ipLayer := &layers.IPv4{
158 Version: 4,
159 TOS: 0x10,
160 TTL: 128,
161 SrcIP: []byte{0, 0, 0, 0},
162 DstIP: []byte{255, 255, 255, 255},
163 Protocol: layers.IPProtocolUDP,
164 }
165
166 udpLayer := &layers.UDP{
167 SrcPort: 68,
168 DstPort: 67,
169 }
170
171 udpLayer.SetNetworkLayerForChecksum(ipLayer)
172 if err := gopacket.SerializeLayers(buffer, options, ethernetLayer, ipLayer, udpLayer, dhcp); err != nil {
173 return nil, err
174 }
175
176 bytes := buffer.Bytes()
177 return bytes, nil
178}
179
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700180func GetDhcpLayer(pkt gopacket.Packet) (*layers.DHCPv4, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700181 layerDHCP := pkt.Layer(layers.LayerTypeDHCPv4)
182 dhcp, _ := layerDHCP.(*layers.DHCPv4)
183 if dhcp == nil {
184 return nil, errors.New("Failed-to-extract-DHCP-layer")
185 }
186 return dhcp, nil
187}
188
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700189func GetDhcpMessageType(dhcp *layers.DHCPv4) (layers.DHCPMsgType, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700190 for _, option := range dhcp.Options {
191 if option.Type == layers.DHCPOptMessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700192 if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeDiscover)}) {
193 return layers.DHCPMsgTypeDiscover, nil
194 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeOffer)}) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700195 return layers.DHCPMsgTypeOffer, nil
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700196 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeRequest)}) {
197 return layers.DHCPMsgTypeRequest, nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700198 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeAck)}) {
199 return layers.DHCPMsgTypeAck, nil
200 } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeRelease)}) {
201 return layers.DHCPMsgTypeRelease, nil
202 } else {
203 msg := fmt.Sprintf("This type %x is not supported", option.Data)
204 return 0, errors.New(msg)
205 }
206 }
207 }
208 return 0, errors.New("Failed to extract MsgType from dhcp")
209}
210
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700211// returns the DHCP Layer type or error if it's not a DHCP Packet
212func GetDhcpPacketType(pkt gopacket.Packet) (string, error) {
213 dhcpLayer, err := GetDhcpLayer(pkt)
214 if err != nil {
215 return "", err
216 }
217 dhcpMessageType, err := GetDhcpMessageType(dhcpLayer)
218 if err != nil {
219 return "", err
220 }
221
222 return dhcpMessageType.String(), nil
223}
224
Matteo Scandolo27428702019-10-11 16:21:16 -0700225func sendDHCPPktIn(msg bbsim.ByteMsg, portNo uint32, stream bbsim.Stream) error {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700226 // FIXME unify sendDHCPPktIn and sendEapolPktIn methods
Matteo Scandolo075b1892019-10-07 12:11:07 -0700227 gemid, err := GetGemPortId(msg.IntfId, msg.OnuId)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700228 if err != nil {
229 dhcpLogger.WithFields(log.Fields{
230 "OnuId": msg.OnuId,
231 "IntfId": msg.IntfId,
232 }).Errorf("Can't retrieve GemPortId: %s", err)
233 return err
234 }
235 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
Matteo Scandolo27428702019-10-11 16:21:16 -0700236 IntfType: "pon",
237 IntfId: msg.IntfId,
238 GemportId: uint32(gemid),
239 Pkt: msg.Bytes,
240 PortNo: portNo,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700241 }}
242
243 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
244 dhcpLogger.Errorf("Fail to send DHCP PktInd indication. %v", err)
245 return err
246 }
247 return nil
248}
249
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700250func sendDHCPRequest(ponPortId uint32, onuId uint32, serialNumber string, portNo uint32, onuHwAddress net.HardwareAddr, offeredIp net.IP, stream openolt.Openolt_EnableIndicationServer) error {
251 dhcp := createDHCPReq(ponPortId, onuId, onuHwAddress, offeredIp)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700252 pkt, err := serializeDHCPPacket(ponPortId, onuId, onuHwAddress, dhcp)
253
254 if err != nil {
255 dhcpLogger.Errorf("Cannot serializeDHCPPacket: %s", err)
256 return err
257 }
258 // NOTE I don't think we need to tag the packet
259 //taggedPkt, err := packetHandlers.PushSingleTag(cTag, pkt)
260
261 msg := bbsim.ByteMsg{
262 IntfId: ponPortId,
263 OnuId: onuId,
264 Bytes: pkt,
265 }
266
Matteo Scandolo27428702019-10-11 16:21:16 -0700267 if err := sendDHCPPktIn(msg, portNo, stream); err != nil {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700268 return err
269 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700270
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700271 dhcpLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700272 "OnuId": onuId,
273 "IntfId": ponPortId,
274 "OnuSn": serialNumber,
275 "OfferedIp": offeredIp.String(),
276 }).Infof("DHCPRequest Sent")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700277 return nil
278}
279
Matteo Scandolo075b1892019-10-07 12:11:07 -0700280func updateDhcpFailed(onuId uint32, ponPortId uint32, serialNumber string, onuStateMachine *fsm.FSM) error {
281 if err := onuStateMachine.Event("dhcp_failed"); err != nil {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700282 dhcpLogger.WithFields(log.Fields{
283 "OnuId": onuId,
284 "IntfId": ponPortId,
285 "OnuSn": serialNumber,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700286 }).Errorf("Error while transitioning ONU State %v", err)
287 return err
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700288 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700289 return nil
290}
291
Matteo Scandolo27428702019-10-11 16:21:16 -0700292func SendDHCPDiscovery(ponPortId uint32, onuId uint32, serialNumber string, portNo uint32, onuStateMachine *fsm.FSM, onuHwAddress net.HardwareAddr, cTag int, stream bbsim.Stream) error {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700293 dhcp := createDHCPDisc(ponPortId, onuId, onuHwAddress)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700294 pkt, err := serializeDHCPPacket(ponPortId, onuId, onuHwAddress, dhcp)
295 if err != nil {
296 dhcpLogger.Errorf("Cannot serializeDHCPPacket: %s", err)
297 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,
305 Bytes: pkt,
306 }
307
Matteo Scandolo27428702019-10-11 16:21:16 -0700308 if err := sendDHCPPktIn(msg, portNo, stream); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700309 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
310 return err
311 }
312 return err
313 }
314 dhcpLogger.WithFields(log.Fields{
315 "OnuId": onuId,
316 "IntfId": ponPortId,
317 "OnuSn": serialNumber,
318 }).Infof("DHCPDiscovery Sent")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700319
320 if err := onuStateMachine.Event("dhcp_discovery_sent"); err != nil {
321 dhcpLogger.WithFields(log.Fields{
322 "OnuId": onuId,
323 "IntfId": ponPortId,
324 "OnuSn": serialNumber,
325 }).Errorf("Error while transitioning ONU State %v", err)
326 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700327 return nil
328}
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700329
Matteo Scandolo27428702019-10-11 16:21:16 -0700330func HandleNextPacket(onuId uint32, ponPortId uint32, serialNumber string, portNo uint32, onuHwAddress net.HardwareAddr, cTag int, onuStateMachine *fsm.FSM, pkt gopacket.Packet, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700331
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700332 dhcpLayer, err := GetDhcpLayer(pkt)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700333 if err != nil {
334 dhcpLogger.WithFields(log.Fields{
335 "OnuId": onuId,
336 "IntfId": ponPortId,
337 "OnuSn": serialNumber,
338 }).Errorf("Can't get DHCP Layer from Packet: %v", err)
339 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
340 return err
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700341 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700342 return err
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700343 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700344 dhcpMessageType, err := GetDhcpMessageType(dhcpLayer)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700345 if err != nil {
346 dhcpLogger.WithFields(log.Fields{
347 "OnuId": onuId,
348 "IntfId": ponPortId,
349 "OnuSn": serialNumber,
350 }).Errorf("Can't get DHCP Message Type from DHCP Layer: %v", err)
351 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
352 return err
353 }
354 return err
355 }
356
357 if dhcpLayer.Operation == layers.DHCPOpReply {
358 if dhcpMessageType == layers.DHCPMsgTypeOffer {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700359 offeredIp := dhcpLayer.YourClientIP
360 if err := sendDHCPRequest(ponPortId, onuId, serialNumber, portNo, onuHwAddress, offeredIp, stream); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700361 dhcpLogger.WithFields(log.Fields{
362 "OnuId": onuId,
363 "IntfId": ponPortId,
364 "OnuSn": serialNumber,
365 }).Errorf("Can't send DHCP Request: %s", err)
366 if err := updateDhcpFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
367 return err
368 }
369 return err
370 }
371 if err := onuStateMachine.Event("dhcp_request_sent"); err != nil {
372 dhcpLogger.WithFields(log.Fields{
373 "OnuId": onuId,
374 "IntfId": ponPortId,
375 "OnuSn": serialNumber,
376 }).Errorf("Error while transitioning ONU State %v", err)
377 }
378
379 } else if dhcpMessageType == layers.DHCPMsgTypeAck {
380 // NOTE once the ack is received we don't need to do anything but change the state
381 if err := onuStateMachine.Event("dhcp_ack_received"); err != nil {
382 dhcpLogger.WithFields(log.Fields{
383 "OnuId": onuId,
384 "IntfId": ponPortId,
385 "OnuSn": serialNumber,
386 }).Errorf("Error while transitioning ONU State %v", err)
387 }
388 dhcpLogger.WithFields(log.Fields{
389 "OnuId": onuId,
390 "IntfId": ponPortId,
391 "OnuSn": serialNumber,
392 }).Infof("DHCP State machine completed")
393 }
394 // NOTE do we need to care about DHCPMsgTypeRelease??
395 } else {
396 dhcpLogger.WithFields(log.Fields{
397 "OnuId": onuId,
398 "IntfId": ponPortId,
399 "OnuSn": serialNumber,
400 }).Warnf("Unsupported DHCP Operation: %s", dhcpLayer.Operation.String())
401 }
402 return nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700403}
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700404
405// This method handle the BBR DHCP Packets
406// BBR does not need to do anything but forward the packets in the correct direction
407func HandleNextBbrPacket(onuId uint32, ponPortId uint32, serialNumber string, sTag int, macAddress net.HardwareAddr, doneChannel chan bool, pkt gopacket.Packet, client openolt.OpenoltClient) error {
408
409 // check if the packet is going:
410 // - outgouing: toward the DHCP
411 // - incoming: toward the ONU
412 isIncoming := packetHandlers.IsIncomingPacket(pkt)
413 log.Tracef("Is Incoming: %t", isIncoming)
414
415 dhcpType, err := GetDhcpPacketType(pkt)
416 if err != nil {
417 log.WithFields(log.Fields{
418 "err": err,
419 }).Fatalf("Can't find DHCP type for packet")
420 }
421
422 srcMac, _ := packetHandlers.GetSrcMacAddressFromPacket(pkt)
423 dstMac, _ := packetHandlers.GetDstMacAddressFromPacket(pkt)
424
425 if isIncoming == true {
426
427 onuPacket := openolt.OnuPacket{
428 IntfId: ponPortId,
429 OnuId: onuId,
430 PortNo: onuId,
431 GemportId: 1,
432 Pkt: pkt.Data(),
433 }
434
435 if _, err := client.OnuPacketOut(context.Background(), &onuPacket); err != nil {
436 log.WithFields(log.Fields{
437 "OnuId": onuId,
438 "IntfId": ponPortId,
439 "OnuSn": serialNumber,
440 "Type": dhcpType,
441 "error": err,
442 }).Error("Failed to send DHCP packet to the ONU")
443 }
444
445 log.WithFields(log.Fields{
446 "OnuId": onuId,
447 "IntfId": ponPortId,
448 "OnuSn": serialNumber,
449 "Type": dhcpType,
450 "DstMac": dstMac,
451 "SrcMac": srcMac,
452 "OnuMac": macAddress,
453 }).Infof("Sent DHCP packet to the ONU")
454
455 // TODO: signal that the ONU has completed
456 dhcpLayer, _ := GetDhcpLayer(pkt)
457 dhcpMessageType, _ := GetDhcpMessageType(dhcpLayer)
458 if dhcpMessageType == layers.DHCPMsgTypeAck {
459 doneChannel <- true
460 }
461
462 } else {
463 // double tag the packet and send it to the NNI
464 // NOTE do we need this in the HandleDHCP Packet?
465 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(sTag, sTag, pkt)
466 if err != nil {
467 log.Error("Failt to add double tag to packet")
468 }
469
470 pkt := openolt.UplinkPacket{
471 IntfId: 0, // BBSim does not care about which NNI, it has only one
472 Pkt: doubleTaggedPkt.Data(),
473 }
474 if _, err := client.UplinkPacketOut(context.Background(), &pkt); err != nil {
475 log.WithFields(log.Fields{
476 "OnuId": onuId,
477 "IntfId": ponPortId,
478 "OnuSn": serialNumber,
479 "Type": dhcpType,
480 "error": err,
481 }).Error("Failed to send DHCP packet out of the NNI Port")
482 }
483 log.WithFields(log.Fields{
484 "OnuId": onuId,
485 "IntfId": ponPortId,
486 "OnuSn": serialNumber,
487 "Type": dhcpType,
488 "DstMac": dstMac,
489 "SrcMac": srcMac,
490 "OnuMac": macAddress,
491 }).Infof("Sent DHCP packet out of the NNI Port")
492 }
493 return nil
494}