blob: 580ea8567152fbf4ab3f5d361e2205c4b49823b8 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301/*
2* Copyright 2022-present Open Networking Foundation
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14 */
15
16package application
17
18import (
Tinoj Joseph07cc5372022-07-18 22:53:51 +053019 "context"
Akash Sonib3abf522022-12-19 13:20:02 +053020 "encoding/hex"
Naveen Sampath04696f72022-06-13 15:19:14 +053021 "errors"
22 "net"
23 "sync"
Tinoj Josephec742f62022-09-29 19:11:10 +053024 "time"
Naveen Sampath04696f72022-06-13 15:19:14 +053025
26 "github.com/google/gopacket"
27 "github.com/google/gopacket/layers"
28
29 cntlr "voltha-go-controller/internal/pkg/controller"
30 "voltha-go-controller/internal/pkg/of"
31 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053032 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053033)
34
35// DhcpRelayState type
36type DhcpRelayState uint8
37
38const (
39 // DhcpRelayStateNone constant
40 DhcpRelayStateNone DhcpRelayState = iota
41 // DhcpRelayStateDiscover constant
42 DhcpRelayStateDiscover
43 // DhcpRelayStateOffer constant
44 DhcpRelayStateOffer
45 // DhcpRelayStateRequest constant
46 DhcpRelayStateRequest
47 // DhcpRelayStateAck constant
48 DhcpRelayStateAck
49 // DhcpRelayStateNAK constant
50 DhcpRelayStateNAK
51 // DhcpRelayStateRelease constant
52 DhcpRelayStateRelease
53)
54
55// RemoteIDType represents data type for various RemoteID types
56type RemoteIDType string
57
58// List of RemoteID types supported
59const (
Akash Sonib3abf522022-12-19 13:20:02 +053060 MACAddress RemoteIDType = "MAC_ADDRESS"
61 CustomRemotedID RemoteIDType = "Custom"
Naveen Sampath04696f72022-06-13 15:19:14 +053062)
63
64// MaxLenDhcpv6DUID constant
65const MaxLenDhcpv6DUID = 130 // 2: DUID-Type, 128: MaxLen of DUID value
66
67// opt82 constant
68const opt82 = 82
69
70// Dhcpv6RelayState type
71type Dhcpv6RelayState uint8
72
73const (
74 // Dhcpv6RelayStateNone constant
75 Dhcpv6RelayStateNone Dhcpv6RelayState = iota
76 // Dhcpv6RelayStateSolicit constant
77 Dhcpv6RelayStateSolicit
78 // Dhcpv6RelayStateReply constant
79 Dhcpv6RelayStateReply
80 // Dhcpv6RelayStateRelease constant
81 Dhcpv6RelayStateRelease
82)
83
84var (
85 // ErrSessionDoNotExist error type
86 ErrSessionDoNotExist = errors.New("Session Doesn't Exist")
87)
88
89// IDhcpRelaySession to get dhcp session field value
90type IDhcpRelaySession interface {
91 GetCircuitID() []byte
92 GetRemoteID() []byte
93 GetNniVlans() (uint16, uint16)
94 GetDhcpState() DhcpRelayState
95 GetDhcpv6State() Dhcpv6RelayState
96 SetDhcpState(DhcpRelayState)
97 SetDhcpv6State(Dhcpv6RelayState)
Tinoj Joseph07cc5372022-07-18 22:53:51 +053098 SetMacAddr(context.Context, net.HardwareAddr)
99 DhcpResultInd(context.Context, *layers.DHCPv4)
100 Dhcpv6ResultInd(cntx context.Context, ipv6Addr net.IP, leaseTime uint32)
Naveen Sampath04696f72022-06-13 15:19:14 +0530101}
102
103// DhcpRelayVnet : The DHCP relay sessions are stored in a map to be retrieved from when
104// a response is received from the network. The map uses the VLANs and the
105// the MAC address as key to finding the service
106// DHCP Relay Virtual Network hosts a set of DHCP relay sessions that belong
107// to the network. It supports two VLANs as its identify. If a single VLAN or
108// no VLAN is to be used, those two should be passed as 4096 (VlanNone)
109type DhcpRelayVnet struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530110 sessions map[[6]byte]IDhcpRelaySession
111 sessionsv6 map[[MaxLenDhcpv6DUID]byte]IDhcpRelaySession
112 sessionLock sync.RWMutex
vinokuma926cb3e2023-03-29 11:41:06 +0530113 OuterVlan uint16
114 InnerVlan uint16
Naveen Sampath04696f72022-06-13 15:19:14 +0530115}
116
117// DhcpNetworks hosts different DHCP networks that in turn hold the DHCP
118// sessions
119type DhcpNetworks struct {
120 Networks map[uint32]*DhcpRelayVnet
121}
122
123func init() {
124 RegisterPacketHandler(DHCPv4, ProcessUDP4Packet)
125 RegisterPacketHandler(DHCPv6, ProcessUDP6Packet)
126}
127
128// NewDhcpRelayVnet is constructor for a DHCP Relay Virtual network
129func NewDhcpRelayVnet(outerVlan uint16, innerVlan uint16) *DhcpRelayVnet {
130 var drv DhcpRelayVnet
131
132 drv.OuterVlan = outerVlan
133 drv.InnerVlan = innerVlan
134 drv.sessions = make(map[[6]byte]IDhcpRelaySession)
135 drv.sessionsv6 = make(map[[MaxLenDhcpv6DUID]byte]IDhcpRelaySession)
136 return &drv
137}
138
139// GetDhcpVnet to add dhcp vnet
140func (dn *DhcpNetworks) GetDhcpVnet(outerVlan uint16, innerVlan uint16) *DhcpRelayVnet {
141 comboVlan := uint32(outerVlan)<<16 + uint32(innerVlan)
142 drv, ok := dn.Networks[comboVlan]
143 if ok {
144 return drv
145 }
146 return nil
147}
148
149// AddDhcpVnet to add dhcp vnet
150func (dn *DhcpNetworks) AddDhcpVnet(outerVlan uint16, innerVlan uint16) *DhcpRelayVnet {
151 comboVlan := uint32(outerVlan)<<16 + uint32(innerVlan)
152 if drv, ok := dn.Networks[comboVlan]; ok {
153 return drv
154 }
155 drv := NewDhcpRelayVnet(outerVlan, innerVlan)
156 dn.Networks[comboVlan] = drv
157 return drv
158}
159
160// NewDhcpNetworks to get new dhcp network
161func NewDhcpNetworks() *DhcpNetworks {
162 var dn DhcpNetworks
163 dn.Networks = make(map[uint32]*DhcpRelayVnet)
164 return &dn
165}
166
167// AddDhcpSession to add dhcp session
168func (dn *DhcpNetworks) AddDhcpSession(pkt gopacket.Packet, session IDhcpRelaySession) error {
169 var key [6]byte
170 ethl := pkt.Layer(layers.LayerTypeEthernet)
171 eth, _ := ethl.(*layers.Ethernet)
172 addr := eth.SrcMAC
173 if len(addr) != 6 {
174 logger.Errorw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
175 return errors.New("Invalid MAC address")
176 }
177 copy(key[:], addr[0:6])
178
179 drv := dn.AddDhcpVnet(session.GetNniVlans())
180
181 drv.sessionLock.Lock()
182 drv.sessions[key] = session
183 drv.sessionLock.Unlock()
184 return nil
185}
186
187// DelDhcpSession to delete dhcp session
188func (dn *DhcpNetworks) DelDhcpSession(pkt gopacket.Packet, session IDhcpRelaySession) {
189 var key [6]byte
190 ethl := pkt.Layer(layers.LayerTypeEthernet)
191 eth, _ := ethl.(*layers.Ethernet)
192 addr := eth.SrcMAC
193 if len(addr) != 6 {
194 logger.Errorw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
195 return
196 }
197 copy(key[:], addr[0:6])
198 drv := dn.AddDhcpVnet(session.GetNniVlans())
199 drv.sessionLock.Lock()
200 delete(drv.sessions, key)
201 drv.sessionLock.Unlock()
202}
203
204// delDhcpSessions to delete dhcp sessions
205func delDhcpSessions(addr net.HardwareAddr, outervlan of.VlanType, innervlan of.VlanType, sessionKey [MaxLenDhcpv6DUID]byte) {
206 var key [6]byte
207 if addr == nil || !NonZeroMacAddress(addr) {
208 logger.Warnw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
209 return
210 }
211 copy(key[:], addr[0:6])
212 drv := dhcpNws.AddDhcpVnet(uint16(outervlan), uint16(innervlan))
213 drv.sessionLock.Lock()
214 delete(drv.sessions, key)
215 delete(drv.sessionsv6, sessionKey)
216 drv.sessionLock.Unlock()
217 logger.Infow(ctx, "DHCP Sessions deleted", log.Fields{"MAC": addr})
218}
219
220// AddDhcp6Session to add dhcpv6 session
221func (dn *DhcpNetworks) AddDhcp6Session(key [MaxLenDhcpv6DUID]byte, session IDhcpRelaySession) error {
222 outerVlan, innerVlan := session.GetNniVlans()
223 logger.Infow(ctx, "Adding Session", log.Fields{"outerVlan": outerVlan, "innerVlan": innerVlan, "Addr": key})
224 drv := dn.AddDhcpVnet(outerVlan, innerVlan)
225 drv.sessionLock.Lock()
226 drv.sessionsv6[key] = session
227 drv.sessionLock.Unlock()
228 return nil
229}
230
231// DelDhcp6Session to delete dhcpv6 session
232func (dn *DhcpNetworks) DelDhcp6Session(key [MaxLenDhcpv6DUID]byte, session IDhcpRelaySession) {
233 outerVlan, innerVlan := session.GetNniVlans()
234 logger.Infow(ctx, "Get Session", log.Fields{"OuterVLAN": outerVlan, "InnerVLAN": innerVlan, "Addr": key})
235 drv := dn.GetDhcpVnet(outerVlan, innerVlan)
236 drv.sessionLock.Lock()
237 delete(drv.sessionsv6, key)
238 drv.sessionLock.Unlock()
239}
240
241// GetDhcpSession to get dhcp session info
242func (dn *DhcpNetworks) GetDhcpSession(outerVlan uint16, innerVlan uint16, addr net.HardwareAddr) (IDhcpRelaySession, error) {
243 var key [6]byte
244 if len(addr) != 6 {
245 logger.Errorw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
246 return nil, errors.New("Invalid MAC address")
247 }
248 copy(key[:], addr[0:6])
249 drv := dn.AddDhcpVnet(outerVlan, innerVlan)
250 drv.sessionLock.RLock()
251 defer drv.sessionLock.RUnlock()
252 if session, ok := drv.sessions[key]; ok {
253 return session, nil
254 }
255 return nil, ErrSessionDoNotExist
256}
257
258// GetDhcp6Session to get Dhcp6Session
259func (dn *DhcpNetworks) GetDhcp6Session(outerVlan uint16, innerVlan uint16, key [MaxLenDhcpv6DUID]byte) (IDhcpRelaySession, error) {
260 logger.Infow(ctx, "Locating Session", log.Fields{"OuterVlan": outerVlan, "InnerVlan": innerVlan, "key": key})
261
262 drv := dn.AddDhcpVnet(outerVlan, innerVlan)
263 drv.sessionLock.RLock()
264 defer drv.sessionLock.RUnlock()
265 if session, ok := drv.sessionsv6[key]; ok {
266 return session, nil
267 }
268 return nil, ErrSessionDoNotExist
269}
270
271// GetVlansFromPacket to get vlans from the packet
272func GetVlansFromPacket(pkt gopacket.Packet) (innerVlan of.VlanType, outerVlan of.VlanType) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530273 vlans := GetVlans(pkt)
274 if len(vlans) == 1 {
275 outerVlan = vlans[0]
276 innerVlan = of.VlanNone
277 } else if len(vlans) == 0 {
278 innerVlan = of.VlanNone
279 outerVlan = of.VlanNone
280 } else {
281 innerVlan = vlans[1]
282 outerVlan = vlans[0]
283 }
284 return
285}
286
287// GetVnetForV4Nni to get vnet for v4 Nni
288func GetVnetForV4Nni(dhcp *layers.DHCPv4, cvlan of.VlanType, svlan of.VlanType, pbit uint8) ([]*VoltPortVnet, error) {
289 var err error
290 var session IDhcpRelaySession
291 var vpvList []*VoltPortVnet
292 logger.Infow(ctx, "Mac Obtained MAC: ", log.Fields{"Addr": dhcp.ClientHWAddr})
293 session, err = dhcpNws.GetDhcpSession(uint16(svlan), uint16(cvlan), dhcp.ClientHWAddr)
294
295 if session != nil {
296 vpv, ok := session.(*VoltPortVnet)
297 logger.Infow(ctx, "Session Exist: VPV found", log.Fields{"VPV": vpv})
298 if ok {
299 vpvList = append(vpvList, vpv)
300 return vpvList, nil
301 }
302 }
303
304 if err == ErrSessionDoNotExist {
305 //No DHCP Session found, find matching VPV to send the packet out
306 logger.Info(ctx, "Session Doesnt Exist: Finding matching VPV")
307 return GetApplication().GetVpvsForDsPkt(cvlan, svlan, dhcp.ClientHWAddr, pbit)
308 }
309 return nil, errors.New("The session retrieved of wrong type")
310}
311
312// GetVnetForV6Nni to get vnet for v6 Nni
313func GetVnetForV6Nni(dhcp *layers.DHCPv6, cvlan of.VlanType, svlan of.VlanType,
314 pbit uint8, clientMAC net.HardwareAddr) ([]*VoltPortVnet, net.HardwareAddr, error) {
315 var err error
316 var session IDhcpRelaySession
317 var vpvList []*VoltPortVnet
318
319 var sessionKey [MaxLenDhcpv6DUID]byte
320
321 clientDuid, decodedDuid := getDhcpv6ClientDUID(dhcp)
322 if clientDuid == nil || decodedDuid == nil {
323 copy(sessionKey[:], clientMAC)
324 } else {
325 copy(sessionKey[:], clientDuid[0:])
326 if decodedDuid.Type == layers.DHCPv6DUIDTypeLLT || decodedDuid.Type == layers.DHCPv6DUIDTypeLL {
327 clientMAC = decodedDuid.LinkLayerAddress
328 }
329 }
330 session, err = dhcpNws.GetDhcp6Session(uint16(svlan), uint16(cvlan), sessionKey)
331 if session != nil {
332 vpv, ok := session.(*VoltPortVnet)
333 logger.Infow(ctx, "Session Exist: VPV found", log.Fields{"VPV": vpv})
334 if ok {
335 vpvList = append(vpvList, vpv)
336 return vpvList, clientMAC, nil
337 }
338 }
339
340 if err == ErrSessionDoNotExist {
341 //No DHCP Session found, find matching VPV to send the packet out
342 logger.Info(ctx, "Session Doesnt Exist: Finding matching VPV")
343 vpvList, err := GetApplication().GetVpvsForDsPkt(cvlan, svlan, clientMAC, pbit)
344 return vpvList, clientMAC, err
345 }
346 return nil, clientMAC, errors.New("The session retrieved of wrong type")
347}
348
349/*
350// getDhcpv4ClientMacAddr to get mac address for dhcpv4 client
351func getDhcpv4ClientMacAddr(pkt gopacket.Packet) net.HardwareAddr {
352 dhcp := pkt.Layer(layers.LayerTypeDHCPv4).(*layers.DHCPv4)
353 logger.Infow(ctx, "Mac Obtained v4: ", log.Fields{"Addr": dhcp.ClientHWAddr})
354 return dhcp.ClientHWAddr
355}
356
357// getDhcpv6ClientMacAddr to get mac address for dhcpv6 client
358func getDhcpv6ClientMacAddr(dhcpv6 *layers.DHCPv6) net.HardwareAddr {
359 var cID layers.DHCPv6Option
360 for _, option := range dhcpv6.Options {
361 if option.Code == layers.DHCPv6OptClientID {
362 cID = option
363 }
364 }
365 duid := &layers.DHCPv6DUID{}
366
367 //If cID is not found, DecodeFromBytes() returns error on empty cID
368 if err := duid.DecodeFromBytes(cID.Data); err == nil {
369 logger.Infow(ctx, "Mac Obtained v6: ", log.Fields{"Addr": duid.LinkLayerAddress, "Option": cID.String()})
370 return duid.LinkLayerAddress
371 }
372 return nil
373}*/
374
375// getDhcpv6ClientDUID to get Dhcpv6 client DUID
376func getDhcpv6ClientDUID(dhcpv6 *layers.DHCPv6) ([]byte, *layers.DHCPv6DUID) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530377 for _, option := range dhcpv6.Options {
378 logger.Debugw(ctx, "DHCPv6 Options", log.Fields{"option": option.Code})
379 if option.Code == layers.DHCPv6OptClientID {
380 duid := &layers.DHCPv6DUID{}
381 err := duid.DecodeFromBytes(option.Data)
382 if err == nil {
383 logger.Infow(ctx, "ClientIdentifier", log.Fields{"DUID": duid, "Option": option.String()})
384 duidLen := len(option.Data)
385 if duidLen > 130 {
386 duidLen = 130
387 }
388 return option.Data[0:duidLen], duid
389 }
390 logger.Errorw(ctx, "Client DUID decode failed", log.Fields{"error": err})
391 break
392 }
393 }
394 logger.Error(ctx, "Client DUID is not present in the packet")
395 return nil, nil
396}
397
398// AddDhcpv4Option82 : DHCPv4 packet operations
399// Addition of DHCP Option 82 which codes circuit-id and remote-id
400// into the packet. This happens as the request is relayed to the
401// DHCP servers on the NNI
402func AddDhcpv4Option82(svc *VoltService, rID []byte, dhcpv4 *layers.DHCPv4) {
403 //NOTE : both cID and rID should not be empty if this function is called
404 cID := svc.GetCircuitID()
405 var data []byte
406 if len(cID) != 0 {
407 data = append(data, 0x01)
408 data = append(data, byte(len(cID)))
409 data = append(data, cID...)
410 }
411 if len(rID) != 0 {
412 data = append(data, 0x02)
413 data = append(data, byte(len(rID)))
414 data = append(data, rID...)
415 }
416
417 if svc.isDataRateAttrPresent() {
418 minDrUs := util.Uint32ToByte(svc.MinDataRateUs)
419 data = append(data, TYPEMINDATAUS)
420 data = append(data, byte(len(minDrUs)))
421 data = append(data, minDrUs...)
422
423 minDrDs := util.Uint32ToByte(svc.MinDataRateDs)
424 data = append(data, TYPEMINDATADS)
425 data = append(data, byte(len(minDrDs)))
426 data = append(data, minDrDs...)
427
428 maxDrUs := util.Uint32ToByte(svc.MaxDataRateUs)
429 data = append(data, TYPEMAXDATAUS)
430 data = append(data, byte(len(maxDrUs)))
431 data = append(data, maxDrUs...)
432
433 maxDrDs := util.Uint32ToByte(svc.MaxDataRateDs)
434 data = append(data, TYPEMAXDATADS)
435 data = append(data, byte(len(maxDrDs)))
436 data = append(data, maxDrDs...)
437 }
438
439 option := layers.NewDHCPOption(82, data)
440 dhcpv4.Options = append(dhcpv4.Options, option)
441}
442
443// DelOption82 : Deletion of option 82 from the packet received on the NNI interface.
444// Once the packet is received, the option 82 is stripped off and the
445// packet is forwarded towards access
446func DelOption82(dhcpv4 *layers.DHCPv4) {
447 for index, option := range dhcpv4.Options {
448 if option.Type == opt82 {
449 dhcpv4.Options = append(dhcpv4.Options[0:index], dhcpv4.Options[index+1:]...)
450 return
451 }
452 }
453}
454
455// DhcpMsgType returns the DHCP message type from the packet
456func DhcpMsgType(dhcp *layers.DHCPv4) layers.DHCPMsgType {
457 for _, option := range dhcp.Options {
458 if option.Type == layers.DHCPOptMessageType {
459 return layers.DHCPMsgType(option.Data[0])
460 }
461 }
462 return layers.DHCPMsgTypeUnspecified
463}
464
465// GetIpv4Addr returns the IP address in the DHCP reply
466func GetIpv4Addr(dhcp *layers.DHCPv4) (net.IP, int64) {
467 var leaseTime uint32
468 for _, opt := range dhcp.Options {
469 if opt.Type == layers.DHCPOptLeaseTime {
470 leaseTime = GetIPv4LeaseTime(opt)
471 }
472 }
473 return dhcp.YourClientIP, int64(leaseTime)
474}
475
vinokuma926cb3e2023-03-29 11:41:06 +0530476// GetIPv4LeaseTime get ip lease time
Naveen Sampath04696f72022-06-13 15:19:14 +0530477func GetIPv4LeaseTime(opt layers.DHCPOption) uint32 {
478 return uint32(opt.Data[0])<<24 | uint32(opt.Data[1])<<16 | uint32(opt.Data[2])<<8 | uint32(opt.Data[3])
479}
480
481// GetIpv6Addr returns the IPv6 address in the DHCPv6 reply
482func GetIpv6Addr(dhcp6 *layers.DHCPv6) (net.IP, uint32) {
483 var ipv6Addr net.IP
484 var leaseTime uint32
485
486 //Check for IANA allocation, if not present, then look for IAPD allocation
487 if dhcp6.MsgType == layers.DHCPv6MsgTypeReply {
488 ipv6Addr, leaseTime = GetIANAAddress(dhcp6)
489 if ipv6Addr == nil {
490 ipv6Addr, leaseTime = GetIAPDAddress(dhcp6)
491 }
492 }
493 return ipv6Addr, leaseTime
494}
495
496// GetIANAAddress returns the IPv6 address in the DHCPv6 reply
497func GetIANAAddress(dhcp6 *layers.DHCPv6) (net.IP, uint32) {
498 var ipv6Addr net.IP
499 var leaseTime uint32
500 if dhcp6.MsgType == layers.DHCPv6MsgTypeReply {
501 for _, o := range dhcp6.Options {
502 if o.Code == layers.DHCPv6OptIANA {
Naveen Sampath04696f72022-06-13 15:19:14 +0530503 iana := &layers.DHCPv6IANA{}
504 err := iana.DecodeFromBytes(o.Data)
505 if err == nil {
506 ipv6Addr = iana.IA.IPv6Addr
507 leaseTime = iana.IA.ValidLifeTime
508 logger.Debugw(ctx, "IPv6 Allocated", log.Fields{"IANA IPv6": ipv6Addr})
509 return ipv6Addr, leaseTime
510 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530511 logger.Warnw(ctx, "Decode of IANA Failed", log.Fields{"Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530512 break
513 }
514 }
515 }
516 return nil, 0
517}
518
519// GetIAPDAddress returns the IPv6 address in the DHCPv6 reply
520func GetIAPDAddress(dhcp6 *layers.DHCPv6) (net.IP, uint32) {
521 var ipv6Addr net.IP
522 var leaseTime uint32
523 if dhcp6.MsgType == layers.DHCPv6MsgTypeReply {
524 for _, o := range dhcp6.Options {
525 if o.Code == layers.DHCPv6OptIAPD {
Naveen Sampath04696f72022-06-13 15:19:14 +0530526 iapd := &layers.DHCPv6IAPD{}
527 if err := iapd.DecodeFromBytes(o.Data); err == nil {
528 ipv6Addr = iapd.PD.Prefix
529 leaseTime = iapd.PD.ValidLifeTime
530 logger.Debugw(ctx, "IPv6 Allocated", log.Fields{"IAPD IPv6": ipv6Addr})
531 break
532 } else {
Tinoj Joseph1d108322022-07-13 10:07:39 +0530533 logger.Warnw(ctx, "Decode of IAPD Failed", log.Fields{"Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530534 break
535 }
536 }
537 }
538 }
539 return ipv6Addr, leaseTime
540}
541
542// ProcessDsDhcpv4Packet : DHCPv4 packet processor functions
543// This function processes DS DHCP packet received on the NNI port.
544// The services are attached to the access ports. Thus, the DHCP
545// session is derived from the list of DHCP sessions stored in the
546// common map. The key for retrieval includes the VLAN tags in the
547// the packet and the MAC address of the client.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530548func (va *VoltApplication) ProcessDsDhcpv4Packet(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530549 // Retrieve the layers to build the outgoing packet. It is not
550 // possible to add/remove layers to the existing packet and thus
551 // the lyayers are extracted to build the outgoing packet
552 eth := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
553 ip := pkt.Layer(layers.LayerTypeIPv4).(*layers.IPv4)
554 udp := pkt.Layer(layers.LayerTypeUDP).(*layers.UDP)
555 dhcp4 := pkt.Layer(layers.LayerTypeDHCPv4).(*layers.DHCPv4)
556 msgType := DhcpMsgType(dhcp4)
557
558 // Need to locate the service from the packet alone as the services
559 // are not attached to NNI port. The service is stored on DHCP relay
560 // application
561 logger.Infow(ctx, "Processing Southbound DS DHCPv4 packet", log.Fields{"Port": port, "Type": msgType})
562
563 // Retrieve the priority and drop eligible flags from the
564 // packet received
565 var priority uint8
566 var dsPbit uint8
567 var dropEligible bool
568 dot1ql := pkt.Layer(layers.LayerTypeDot1Q)
569 if dot1ql != nil {
570 dot1q := dot1ql.(*layers.Dot1Q)
571 priority = dot1q.Priority
572 dropEligible = dot1q.DropEligible
573 }
574
575 pktInnerlan, pktOuterlan := GetVlansFromPacket(pkt)
576 vpvList, _ := GetVnetForV4Nni(dhcp4, pktInnerlan, pktOuterlan, priority)
577 if len(vpvList) == 0 {
578 logger.Warn(ctx, "VNET couldn't be found for NNI")
579 return
580 }
581
582 // The DHCP option 82, if it exists is removed from the packet
583 DelOption82(dhcp4)
584 ipAddr, leaseTime := GetIpv4Addr(dhcp4)
585
586 for _, vpv := range vpvList {
587 dsPbit = vpv.GetRemarkedPriority(priority)
588 // Raise DHCP ACK/NCK indication
589 if vpv.DhcpRelay {
590 // Inform dhcp response information to dhcp server handler
591 dhcpResponseReceived(uint16(vpv.CVlan), uint16(vpv.SVlan))
592 // Process the Ack/Nack to track to state of the IP layer of the connection
593 if msgType == layers.DHCPMsgTypeAck || msgType == layers.DHCPMsgTypeNak {
594 // Install DS HSIA flows after DHCP ACK.
595 if msgType == layers.DHCPMsgTypeAck {
596 // Voltha will push US and DS HSIA flow on receivng the DS HSIA
597 // flow installation request, VGC to update US HSIA flow with leanrt MAC.
598 // separate go rotuine is spawned to avoid drop of ACK packet
599 // as HSIA flows will be deleted if new MAC is learnt.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530600 go vpv.SetMacAddr(cntx, dhcp4.ClientHWAddr)
Naveen Sampath04696f72022-06-13 15:19:14 +0530601 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530602 vpv.DhcpResultInd(cntx, dhcp4)
Naveen Sampath04696f72022-06-13 15:19:14 +0530603 }
604 raiseDHCPv4Indication(msgType, vpv, dhcp4.ClientHWAddr, ipAddr, dsPbit, device, leaseTime)
605 }
606
607 // Create the outgoing bufer and set the checksum in the packet
608 buff := gopacket.NewSerializeBuffer()
609 if err := udp.SetNetworkLayerForChecksum(ip); err != nil {
610 logger.Error(ctx, "Error in setting checksum")
611 return
612 }
613 opts := gopacket.SerializeOptions{
614 FixLengths: true,
615 ComputeChecksums: true,
616 }
617
618 cTagType := layers.EthernetTypeIPv4
619 eth.EthernetType = layers.EthernetTypeDot1Q
620
621 var pktLayers []gopacket.SerializableLayer
622 pktLayers = append(pktLayers, eth)
623
624 var qVlans []of.VlanType
625 var qVlanLayers []gopacket.SerializableLayer
626
627 if vpv.AllowTransparent {
628 vlanThreshold := 2
629 // In case of ONU_CVLAN or OLT_SVLAN, the DS pkts have single configured vlan
630 // In case of ONU_CVLAN_OLT_SVLAN or OLT_CVLAN_OLT_SVLAN, the DS pkts have 2 configured vlan
631 // Based on that, the no. of vlans should be ignored to get only transparent vlans
632 if vpv.VlanControl == ONUCVlan || vpv.VlanControl == OLTSVlan || vpv.VlanControl == None {
633 vlanThreshold = 1
634 }
635 nxtLayer := layers.EthernetTypeDot1Q
636 if vlans := GetVlans(pkt); len(vlans) > vlanThreshold {
637 qVlans = vlans[vlanThreshold:]
638 cTagType = layers.EthernetTypeDot1Q
639 }
640 for i, qVlan := range qVlans {
641 vlan := uint16(qVlan)
642 if i == (len(qVlans) - 1) {
643 nxtLayer = layers.EthernetTypeIPv4
644 }
645 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
646 qVlanLayers = append(qVlanLayers, qdot1q)
647 }
648 }
649 switch vpv.VlanControl {
650 case ONUCVlanOLTSVlan:
651 cdot1q := &layers.Dot1Q{Priority: dsPbit, VLANIdentifier: uint16(vpv.CVlan), DropEligible: dropEligible, Type: cTagType}
652 pktLayers = append(pktLayers, cdot1q)
653 case ONUCVlan,
654 None:
655 sdot1q := &layers.Dot1Q{Priority: dsPbit, VLANIdentifier: uint16(vpv.SVlan), DropEligible: dropEligible, Type: cTagType}
656 pktLayers = append(pktLayers, sdot1q)
657 case OLTCVlanOLTSVlan,
658 OLTSVlan:
659 udot1q := &layers.Dot1Q{Priority: dsPbit, VLANIdentifier: uint16(vpv.UniVlan), DropEligible: dropEligible, Type: cTagType}
660 pktLayers = append(pktLayers, udot1q)
661 default:
662 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
663 }
664
665 pktLayers = append(pktLayers, qVlanLayers...)
666 pktLayers = append(pktLayers, ip)
667 pktLayers = append(pktLayers, udp)
668 pktLayers = append(pktLayers, dhcp4)
669 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
670 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
671 logger.Errorw(ctx, "Packet Serialization Failed", log.Fields{"Reason": err.Error()})
672 return
673 }
674
675 if err := cntlr.GetController().PacketOutReq(device, vpv.Port, port, buff.Bytes(), false); err != nil {
Akash Sonib3abf522022-12-19 13:20:02 +0530676 logger.Errorw(ctx, "PacketOutReq Failed", log.Fields{"Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +0530677 }
678 }
679}
680
681// raiseDHCPv4Indication process DHCPv4 packet and raise indication
682func raiseDHCPv4Indication(msgType layers.DHCPMsgType, vpv *VoltPortVnet, smac net.HardwareAddr,
683 ip net.IP, pktPbit uint8, device string, leaseTime int64) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530684 logger.Debugw(ctx, "Processing Dhcpv4 packet", log.Fields{"ethsrcMac": smac.String(),
685 "MacLearningInVPV": vpv.MacLearning, "MacConfigured": vpv.MacAddr, "dhcpType": msgType,
686 "vlanPriority": pktPbit, "VPVLearntMac": vpv.LearntMacAddr})
687
688 matchServiceAndRaiseInd := func(key, value interface{}) bool {
689 // walk through all svcs under vpv and match pbit with packet.
690 svc := value.(*VoltService)
691
692 if svc.IsPbitExist(of.PbitType(pktPbit)) {
693 logger.Debugw(ctx, "Matching Pbit found in service config", log.Fields{"ServiceName": svc.Name, "Pbit": pktPbit})
694 return false
695 }
696 return true
697 }
698
699 switch msgType {
700 case layers.DHCPMsgTypeDiscover, layers.DHCPMsgTypeRequest:
701 if msgType == layers.DHCPMsgTypeDiscover {
702 vpv.SetDhcpState(DhcpRelayStateDiscover)
703 } else if msgType == layers.DHCPMsgTypeRequest {
704 vpv.SetDhcpState(DhcpRelayStateRequest)
705 }
706 // Reset learnt mac address in case of DHCPv4 release
707 case layers.DHCPMsgTypeRelease:
708 vpv.LearntMacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
709 vpv.services.Range(matchServiceAndRaiseInd)
710 vpv.SetDhcpState(DhcpRelayStateRelease)
711
712 case layers.DHCPMsgTypeAck, layers.DHCPMsgTypeNak:
713 vpv.services.Range(matchServiceAndRaiseInd)
714 if msgType == layers.DHCPMsgTypeAck {
715 vpv.SetDhcpState(DhcpRelayStateAck)
716 } else if msgType == layers.DHCPMsgTypeNak {
717 vpv.SetDhcpState(DhcpRelayStateNAK)
718 }
719 case layers.DHCPMsgTypeOffer:
720 vpv.SetDhcpState(DhcpRelayStateOffer)
721 }
722}
723
724// raiseDHCPv6Indication process DHCPv6 packet and raise indication
725func raiseDHCPv6Indication(msgType layers.DHCPv6MsgType, vpv *VoltPortVnet,
726 smac net.HardwareAddr, ip net.IP, pktPbit uint8, device string, leaseTime uint32) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530727 logger.Debugw(ctx, "Processing DHCPv6 packet", log.Fields{"dhcpType": msgType,
728 "vlanPriority": pktPbit, "dhcpClientMac": smac.String(),
729 "MacLearningInVPV": vpv.MacLearning, "MacConfigured": vpv.MacAddr,
730 "VPVLearntMac": vpv.LearntMacAddr})
731
732 matchServiceAndRaiseInd := func(key, value interface{}) bool {
733 svc := value.(*VoltService)
734 if svc.IsPbitExist(of.PbitType(pktPbit)) {
735 logger.Debugw(ctx, "Matching Pbit found in service config", log.Fields{"ServiceName": svc.Name, "Pbit": pktPbit})
736 return false
737 }
738 return true
739 }
740
741 switch msgType {
742 case layers.DHCPv6MsgTypeSolicit:
743 vpv.SetDhcpv6State(Dhcpv6RelayStateSolicit)
744 // Reset learnt mac address in case of DHCPv6 release
745 case layers.DHCPv6MsgTypeRelease:
746 vpv.LearntMacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
747 vpv.services.Range(matchServiceAndRaiseInd)
748 vpv.SetDhcpv6State(Dhcpv6RelayStateRelease)
749
750 case layers.DHCPv6MsgTypeReply:
751 vpv.services.Range(matchServiceAndRaiseInd)
752 vpv.SetDhcpv6State(Dhcpv6RelayStateReply)
753 }
754}
755
756// ProcessUsDhcpv4Packet : The US DHCPv4 packet is identified the DHCP OP in the packet. A request is considered upstream
757// and the service associated with the packet is located by the port and VLANs in the packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530758func (va *VoltApplication) ProcessUsDhcpv4Packet(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530759 // We received the packet on an access port and the service for the packet can be
760 // gotten from the port and the packet
761 vpv, svc := va.GetVnetFromPkt(device, port, pkt)
762 if vpv == nil {
763 logger.Warn(ctx, "VNET couldn't be found from packet")
764 return
765 }
766
767 outport, _ := va.GetNniPort(device)
768 if outport == "" || outport == "0" {
769 logger.Errorw(ctx, "NNI Port not found for device. Dropping Packet", log.Fields{"NNI": outport})
770 return
771 }
772
773 // Extract the layers in the packet to prepare the outgoing packet
774 // We use the layers to build the outgoing packet from scratch as
775 // the packet received can't be modified to add/remove layers
776 eth := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
777 ip := pkt.Layer(layers.LayerTypeIPv4).(*layers.IPv4)
778 udp := pkt.Layer(layers.LayerTypeUDP).(*layers.UDP)
779 dhcp4 := pkt.Layer(layers.LayerTypeDHCPv4).(*layers.DHCPv4)
780 msgType := DhcpMsgType(dhcp4)
781 logger.Infow(ctx, "Processing Southbound US DHCPv4 packet", log.Fields{"Device": device, "Port": port, "Type": msgType})
782
783 // Learn the 8021P values from the packet received
784 var priority uint8
785 var dropEligible bool
786 dot1ql := pkt.Layer(layers.LayerTypeDot1Q)
787 if dot1ql != nil {
788 dot1q := dot1ql.(*layers.Dot1Q)
789 priority = dot1q.Priority
790 dropEligible = dot1q.DropEligible
791 }
792 // If this is the first message in the DHCP sequence, the service
793 // is added to the DHCP relay application. The reply packets locate
794 // the associated service/session from the relay application.
795 if msgType == layers.DHCPMsgTypeDiscover || msgType == layers.DHCPMsgTypeRequest {
796 if err := dhcpNws.AddDhcpSession(pkt, vpv); err != nil {
797 logger.Errorw(ctx, "Adding dhcp session failed", log.Fields{"Error": err})
798 }
799 }
800
801 // Raise mac-learnt(DHCP Discover) indication when mac learning is enabled and learnt mac
802 // is not same as received mac address. If mac learning disabled, we have mac address in the
803 // service configuration. Hence mac learnt indication is not raised
804 // Reset learnt mac address in case of DHCP release and raise the indication
805 if vpv.DhcpRelay {
806 // If this is the first message in the DHCP sequence, the service
807 // is added to the DHCP relay application. The reply packets locate
808 // the associated service/session from the relay application.
809 // DS HSIA flows will be added after DHCP ACK .
810 if msgType == layers.DHCPMsgTypeDiscover || msgType == layers.DHCPMsgTypeRequest {
811 if !util.MacAddrsMatch(vpv.MacAddr, dhcp4.ClientHWAddr) {
812 // MAC is different and relearning is disabled.
813 if NonZeroMacAddress(vpv.MacAddr) && vpv.MacLearning == Learn {
814 // update learnt mac for debug purpose
815 vpv.LearntMacAddr = dhcp4.ClientHWAddr
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530816 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530817 logger.Warnw(ctx, "Dropping the packet Mac relearn is disabled",
818 log.Fields{"vpv.MacAddr": vpv.MacAddr, "LearntMac": dhcp4.ClientHWAddr})
819 return
820 }
821 expectedPort := va.GetMacInPortMap(dhcp4.ClientHWAddr)
822 if expectedPort != "" && expectedPort != vpv.Port {
823 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-dhcp-message", log.Fields{"MsgType": msgType, "ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": dhcp4.ClientHWAddr.String()})
824 return
825 }
826 }
827 }
828 raiseDHCPv4Indication(msgType, vpv, dhcp4.ClientHWAddr, vpv.Ipv4Addr, priority, device, 0)
829
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530830 // Check IsOption82Enabled flag in configuration. if true(enabled), add option82 into dhcpv4 header.
Naveen Sampath04696f72022-06-13 15:19:14 +0530831 // Remote id can be custom or mac address.
832 // If remote id is custom, then add service will carry the remote id
833 // If remote id is mac address, and if mac is configured, then add service will carry the remote id
834 // If remote id is mac address, in mac learning case, then mac has to be taken from dhcp packet
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530835 if svc.IsOption82Enabled {
Naveen Sampath04696f72022-06-13 15:19:14 +0530836 var remoteID []byte
837 if svc.RemoteIDType == string(MACAddress) {
838 remoteID = []byte((dhcp4.ClientHWAddr).String())
839 } else if svc.RemoteID != nil {
840 remoteID = svc.RemoteID
841 }
842 AddDhcpv4Option82(svc, remoteID, dhcp4)
843 }
844 }
845
846 buff := gopacket.NewSerializeBuffer()
847 if err := udp.SetNetworkLayerForChecksum(ip); err != nil {
848 logger.Error(ctx, "Error in setting checksum")
849 return
850 }
851 opts := gopacket.SerializeOptions{
852 FixLengths: true,
853 ComputeChecksums: true,
854 }
855
856 cTagType := layers.EthernetTypeIPv4
857 outerVlan, innerVlan := vpv.GetNniVlans()
858 logger.Debugw(ctx, "Vnet Vlans", log.Fields{"Svlan": outerVlan, "Cvlan": innerVlan})
859 eth.EthernetType = vpv.SVlanTpid
860
861 var pktLayers []gopacket.SerializableLayer
862 pktLayers = append(pktLayers, eth)
863
864 var qVlans []of.VlanType
865 var qVlanLayers []gopacket.SerializableLayer
866
867 if vpv.AllowTransparent {
868 nxtLayer := layers.EthernetTypeDot1Q
869 if vlans := GetVlans(pkt); len(vlans) > 1 {
870 qVlans = vlans[1:]
871 logger.Debugw(ctx, "Q Vlans", log.Fields{"Vlan List": qVlans})
872 cTagType = layers.EthernetTypeDot1Q
873 }
874 for i, qVlan := range qVlans {
875 vlan := uint16(qVlan)
876 if i == (len(qVlans) - 1) {
877 nxtLayer = layers.EthernetTypeIPv4
878 }
879 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
880 qVlanLayers = append(qVlanLayers, qdot1q)
881 }
882 }
883 switch vpv.VlanControl {
884 case ONUCVlanOLTSVlan,
885 OLTCVlanOLTSVlan:
886 sdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: layers.EthernetTypeDot1Q}
887 pktLayers = append(pktLayers, sdot1q)
888 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: innerVlan, DropEligible: dropEligible, Type: cTagType}
889 pktLayers = append(pktLayers, cdot1q)
890 case ONUCVlan,
891 OLTSVlan,
892 None:
893 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: cTagType}
894 pktLayers = append(pktLayers, cdot1q)
895 default:
896 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
897 }
898
899 pktLayers = append(pktLayers, qVlanLayers...)
900 pktLayers = append(pktLayers, ip)
901 pktLayers = append(pktLayers, udp)
902 pktLayers = append(pktLayers, dhcp4)
903 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
904 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
905 return
906 }
907
908 // Now the packet constructed is output towards the switch to be emitted on
909 // the NNI port
910 if err := cntlr.GetController().PacketOutReq(device, outport, port, buff.Bytes(), false); err != nil {
Akash Sonib3abf522022-12-19 13:20:02 +0530911 logger.Errorw(ctx, "PacketOutReq Failed", log.Fields{"Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +0530912 }
913 if vpv.DhcpRelay {
914 // Inform dhcp request information to dhcp server handler
915 dhcpRequestReceived(uint16(vpv.CVlan), uint16(vpv.SVlan), eth.SrcMAC.String())
916 }
917}
918
919// ProcessUDP4Packet : CallBack function registered with application to handle DHCP packetIn
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530920func ProcessUDP4Packet(cntx context.Context, device string, port string, pkt gopacket.Packet) {
921 GetApplication().ProcessUDP4Packet(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530922}
923
924// ProcessUDP4Packet : The packet is a UDP packet and currently only DHCP relay application is supported
925// We determine the packet direction and process it based on the direction
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530926func (va *VoltApplication) ProcessUDP4Packet(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530927 // Currently DHCP is the only application supported by the application
vinokuma926cb3e2023-03-29 11:41:06 +0530928 // We check for DHCP before proceeding further. In future, this could be
Naveen Sampath04696f72022-06-13 15:19:14 +0530929 // based on registration and the callbacks
930 dhcpl := pkt.Layer(layers.LayerTypeDHCPv4)
931 if dhcpl == nil {
932 return
933 }
934 //logger.Debugw(ctx, "Received Packet In", log.Fields{"Pkt": hex.EncodeToString(pkt.Data())})
935 dhcp4 := pkt.Layer(layers.LayerTypeDHCPv4).(*layers.DHCPv4)
936 if dhcp4.Operation == layers.DHCPOpRequest {
937 // This is treated as an upstream packet in the VOLT application
938 // as VOLT serves access subscribers who use DHCP to acquire IP
939 // address and these packets go upstream to the network
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530940 va.ProcessUsDhcpv4Packet(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530941 } else {
942 // This is a downstream packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530943 va.ProcessDsDhcpv4Packet(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530944 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530945}
946
947// ProcessUDP6Packet : CallBack function registered with application to handle DHCPv6 packetIn
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530948func ProcessUDP6Packet(cntx context.Context, device string, port string, pkt gopacket.Packet) {
949 GetApplication().ProcessUDP6Packet(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530950}
951
952// ProcessUDP6Packet : As a LDRA node, we expect to see only RelayReply from the DHCP server and we always
953// pack the received request and send it to the server as a RelayForward message
954// We expect to see Solicit, Request in the most normal cases. Before the lease expires
955// we should also see Renew. However, we should always pack the US message by adding
956// additional option that identifies to the server that the DHCP packet is forwarded
957// by an LDRA node.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530958func (va *VoltApplication) ProcessUDP6Packet(cntx context.Context, device string, port string, pkt gopacket.Packet) []byte {
Naveen Sampath04696f72022-06-13 15:19:14 +0530959 dhcpl := pkt.Layer(layers.LayerTypeDHCPv6)
960 if dhcpl == nil {
961 return nil
962 }
963 logger.Infow(ctx, "Processing DHCPv6 packet", log.Fields{"Port": port})
964 dhcpv6 := dhcpl.(*layers.DHCPv6)
965 switch dhcpv6.MsgType {
966 case layers.DHCPv6MsgTypeSolicit, layers.DHCPv6MsgTypeRequest, layers.DHCPv6MsgTypeRenew,
967 layers.DHCPv6MsgTypeRelease, layers.DHCPv6MsgTypeRebind, layers.DHCPv6MsgTypeInformationRequest,
968 layers.DHCPv6MsgTypeDecline:
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530969 va.ProcessUsDhcpv6Packet(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530970 case layers.DHCPv6MsgTypeAdvertise, layers.DHCPv6MsgTypeConfirm, layers.DHCPv6MsgTypeReconfigure:
971 logger.Warnw(ctx, "SouthBound DHCPv6 DS Messages Expected For a Relay Agent", log.Fields{"Type": dhcpv6.MsgType})
972 case layers.DHCPv6MsgTypeRelayForward:
973 logger.Warn(ctx, "As the first DHCPv6 Relay Agent, Unexpected Relay Forward")
974 case layers.DHCPv6MsgTypeRelayReply:
975 // We received a response from the server
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530976 va.ProcessDsDhcpv6Packet(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530977 }
978 return nil
979}
980
981// GetRelayReplyBytes to get relay reply bytes
982func GetRelayReplyBytes(dhcp6 *layers.DHCPv6) []byte {
983 for _, o := range dhcp6.Options {
984 logger.Infow(ctx, "Received Option", log.Fields{"Code": o.Code})
985 if o.Code == layers.DHCPv6OptRelayMessage {
986 return o.Data
987 }
988 }
989 return nil
990}
991
992// BuildRelayFwd to build forward relay
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530993func BuildRelayFwd(paddr net.IP, intfID []byte, remoteID []byte, payload []byte, isOption82Enabled bool, dhcpRelay bool) *layers.DHCPv6 {
Naveen Sampath04696f72022-06-13 15:19:14 +0530994 dhcp6 := &layers.DHCPv6{MsgType: layers.DHCPv6MsgTypeRelayForward, LinkAddr: net.ParseIP("::"), PeerAddr: []byte(paddr)}
995 dhcp6.Options = append(dhcp6.Options, layers.NewDHCPv6Option(layers.DHCPv6OptRelayMessage, payload))
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530996 // Check IsOption82Enabled flag in configuration. if true(enabled), add remoteID and circuitID into dhcpv6 header.
Naveen Sampath04696f72022-06-13 15:19:14 +0530997 if dhcpRelay {
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530998 if isOption82Enabled {
Naveen Sampath04696f72022-06-13 15:19:14 +0530999 remote := &layers.DHCPv6RemoteId{RemoteId: remoteID}
1000 if len(remoteID) != 0 {
1001 dhcp6.Options = append(dhcp6.Options, layers.NewDHCPv6Option(layers.DHCPv6OptRemoteID, remote.Encode()))
1002 }
1003 if len(intfID) != 0 {
1004 intf := &layers.DHCPv6IntfId{Data: intfID}
1005 dhcp6.Options = append(dhcp6.Options, layers.NewDHCPv6Option(layers.DHCPv6OptInterfaceID, intf.Encode()))
1006 }
1007 }
1008 }
1009 return dhcp6
1010}
1011
vinokuma926cb3e2023-03-29 11:41:06 +05301012// nolint: gocyclo
Naveen Sampath04696f72022-06-13 15:19:14 +05301013// ProcessUsDhcpv6Packet to rpocess upstream DHCPv6 packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301014func (va *VoltApplication) ProcessUsDhcpv6Packet(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301015 // We received the packet on an access port and the service for the packet can be
1016 // gotten from the port and the packet
1017 logger.Infow(ctx, "Processing Southbound US DHCPv6 packet", log.Fields{"Port": port})
1018 logger.Debugw(ctx, "Packet IN", log.Fields{"Pkt": hex.EncodeToString(pkt.Data())})
1019 vpv, svc := va.GetVnetFromPkt(device, port, pkt)
1020 if vpv == nil {
1021 logger.Warn(ctx, "VNET couldn't be found from packet")
1022 return
1023 }
1024
1025 outport, _ := va.GetNniPort(device)
1026 if outport == "" || outport == "0" {
1027 logger.Errorw(ctx, "NNI Port not found for device. Dropping Packet", log.Fields{"NNI": outport})
1028 return
1029 }
1030
1031 // Extract the layers in the packet to prepare the outgoing packet
1032 // We use the layers to build the outgoing packet from scratch as
1033 // the packet received can't be modified to add/remove layers
1034 eth := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
1035 ip := pkt.Layer(layers.LayerTypeIPv6).(*layers.IPv6)
1036 udp := pkt.Layer(layers.LayerTypeUDP).(*layers.UDP)
1037 idhcp6 := pkt.Layer(layers.LayerTypeDHCPv6).(*layers.DHCPv6)
1038
1039 // Remote id can be custom or mac address.
1040 // If remote id is custom, then add service will carry the remote id
1041 // If remote id is mac address, and if mac is configured, then add service will carry the remote id
1042 // If remote id is mac address, in mac learning case, then mac has to be taken from dhcp packet
1043 var remoteID []byte
1044 if svc.RemoteIDType == string(MACAddress) {
1045 remoteID = []byte((eth.SrcMAC).String())
1046 } else if svc.RemoteID != nil {
1047 remoteID = svc.RemoteID
1048 }
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +05301049 dhcp6 := BuildRelayFwd(ip.SrcIP, svc.GetCircuitID(), remoteID, udp.Payload, svc.IsOption82Enabled, vpv.DhcpRelay)
Naveen Sampath04696f72022-06-13 15:19:14 +05301050
1051 var sourceMac = eth.SrcMAC
1052 var sessionKey [MaxLenDhcpv6DUID]byte
1053
1054 clientDuid, decodedDuid := getDhcpv6ClientDUID(idhcp6)
1055 if clientDuid == nil || decodedDuid == nil {
1056 copy(sessionKey[:], eth.SrcMAC)
1057 } else {
1058 copy(sessionKey[:], clientDuid[0:])
1059 if decodedDuid.Type == layers.DHCPv6DUIDTypeLLT || decodedDuid.Type == layers.DHCPv6DUIDTypeLL {
1060 sourceMac = decodedDuid.LinkLayerAddress
1061 }
1062 }
1063 // Learn the 8021P values from the packet received
1064 var priority uint8
1065 var dropEligible bool
1066 dot1ql := pkt.Layer(layers.LayerTypeDot1Q)
1067 if dot1ql != nil {
1068 dot1q := dot1ql.(*layers.Dot1Q)
1069 priority = dot1q.Priority
1070 dropEligible = dot1q.DropEligible
1071 }
1072 if idhcp6.MsgType == layers.DHCPv6MsgTypeSolicit {
1073 if err := dhcpNws.AddDhcp6Session(sessionKey, vpv); err != nil {
1074 logger.Errorw(ctx, "Adding dhcpv6 session failed", log.Fields{"Error": err})
1075 }
1076 vpv.DHCPv6DUID = sessionKey
1077 }
1078
1079 // Raise mac-learnt(DHCPv6MsgTypeSolicit) indication when mac learning is enabled and learnt mac
1080 // is not same as received mac address. If mac learning disabled, we have mac address in the
1081 // service configuration. Hence mac learnt indication is not raised
1082 if vpv.DhcpRelay {
1083 if idhcp6.MsgType == layers.DHCPv6MsgTypeSolicit {
1084 if !util.MacAddrsMatch(vpv.MacAddr, sourceMac) {
1085 // MAC is different and relearning is disabled.
1086 if NonZeroMacAddress(vpv.MacAddr) && vpv.MacLearning == Learn {
1087 // update learnt mac for debug purpose
1088 vpv.LearntMacAddr = sourceMac
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301089 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301090 logger.Warnw(ctx, "Dropping the packet Mac relearn is disabled",
1091 log.Fields{"vpv.MacAddr": vpv.MacAddr, "LearntMac": sourceMac})
1092 return
1093 }
1094 expectedPort := va.GetMacInPortMap(sourceMac)
1095 if expectedPort != "" && expectedPort != vpv.Port {
1096 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-dhcp-message", log.Fields{"MsgType": idhcp6.MsgType, "ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": sourceMac.String()})
1097 return
1098 }
1099 }
1100 }
1101 raiseDHCPv6Indication(idhcp6.MsgType, vpv, sourceMac, vpv.Ipv6Addr, priority, device, 0)
1102 }
1103
1104 // Create the buffer and the encode options for the outgoing packet
1105 buff := gopacket.NewSerializeBuffer()
1106 if err := udp.SetNetworkLayerForChecksum(ip); err != nil {
1107 logger.Error(ctx, "Error in setting checksum")
1108 return
1109 }
1110 opts := gopacket.SerializeOptions{
1111 FixLengths: true,
1112 ComputeChecksums: true,
1113 }
1114
1115 cTagType := layers.EthernetTypeIPv6
1116 outerVlan, innerVlan := vpv.GetNniVlans()
1117 eth.EthernetType = vpv.SVlanTpid
1118
1119 var pktLayers []gopacket.SerializableLayer
1120 pktLayers = append(pktLayers, eth)
1121
1122 var qVlans []of.VlanType
1123 var qVlanLayers []gopacket.SerializableLayer
1124
1125 if vpv.AllowTransparent {
1126 nxtLayer := layers.EthernetTypeDot1Q
1127 if vlans := GetVlans(pkt); len(vlans) > 1 {
1128 qVlans = vlans[1:]
1129 cTagType = layers.EthernetTypeDot1Q
1130 }
1131 for i, qVlan := range qVlans {
1132 vlan := uint16(qVlan)
1133 if i == (len(qVlans) - 1) {
1134 nxtLayer = layers.EthernetTypeIPv6
1135 }
1136 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
1137 qVlanLayers = append(qVlanLayers, qdot1q)
1138 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301139 }
1140 switch vpv.VlanControl {
1141 case ONUCVlanOLTSVlan,
1142 OLTCVlanOLTSVlan:
1143 sdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: layers.EthernetTypeDot1Q}
1144 pktLayers = append(pktLayers, sdot1q)
1145 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: innerVlan, DropEligible: dropEligible, Type: cTagType}
1146 pktLayers = append(pktLayers, cdot1q)
1147 case ONUCVlan,
1148 OLTSVlan,
1149 None:
1150 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: cTagType}
1151 pktLayers = append(pktLayers, cdot1q)
1152 default:
1153 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
1154 }
1155
1156 pktLayers = append(pktLayers, qVlanLayers...)
1157 pktLayers = append(pktLayers, ip)
1158 pktLayers = append(pktLayers, udp)
1159 pktLayers = append(pktLayers, dhcp6)
1160 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
1161 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
1162 return
1163 }
1164 // Now the packet constructed is output towards the switch to be emitted on
1165 // the NNI port
1166 if err := cntlr.GetController().PacketOutReq(device, outport, port, buff.Bytes(), false); err != nil {
Akash Sonib3abf522022-12-19 13:20:02 +05301167 logger.Errorw(ctx, "PacketOutReq Failed", log.Fields{"Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301168 }
1169 if vpv.DhcpRelay {
1170 // Inform dhcp request information to dhcp server handler
1171 dhcpRequestReceived(uint16(vpv.CVlan), uint16(vpv.SVlan), eth.SrcMAC.String())
1172 }
1173}
1174
1175// GetDhcpv6 to get dhcpv6 info
1176func GetDhcpv6(payload []byte) (*layers.DHCPv6, error) {
1177 pkt := gopacket.NewPacket(payload, layers.LayerTypeDHCPv6, gopacket.Default)
1178 if dl := pkt.Layer(layers.LayerTypeDHCPv6); dl != nil {
1179 if dhcp6, ok := dl.(*layers.DHCPv6); ok {
1180 return dhcp6, nil
1181 }
1182 }
1183 return nil, errors.New("Failed to decode DHCPv6")
1184}
1185
1186// ProcessDsDhcpv6Packet to process downstream dhcpv6 packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301187func (va *VoltApplication) ProcessDsDhcpv6Packet(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301188 logger.Infow(ctx, "Processing Southbound DS DHCPv6 packet", log.Fields{"Port": port})
1189 logger.Debugw(ctx, "Packet IN", log.Fields{"Pkt": hex.EncodeToString(pkt.Data())})
1190
1191 // Retrieve the layers to build the outgoing packet. It is not
1192 // possible to add/remove layers to the existing packet and thus
1193 // the lyayers are extracted to build the outgoing packet
1194 // The DHCP layer is handled differently. The Relay-Reply option
1195 // of DHCP is extracted and is made the UDP payload.
1196 eth := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
1197 ip := pkt.Layer(layers.LayerTypeIPv6).(*layers.IPv6)
1198 udp := pkt.Layer(layers.LayerTypeUDP).(*layers.UDP)
1199 idhcp6 := pkt.Layer(layers.LayerTypeDHCPv6).(*layers.DHCPv6)
1200 //var dhcp6 *layers.DHCPv6
1201 var payload []byte
1202 if payload = GetRelayReplyBytes(idhcp6); payload == nil {
1203 logger.Warn(ctx, "Didn't Receive RelayMessage IE")
1204 return
1205 }
1206
1207 dhcp6, err := GetDhcpv6(payload)
1208 if err != nil {
1209 logger.Warnw(ctx, "DHCPv6 Decode Failed", log.Fields{"Reason": err.Error()})
1210 return
1211 }
1212
1213 // Learn the 8021P values from the packet received
1214 var priority uint8
1215 var dsPbit uint8
1216 var dropEligible bool
1217 dot1ql := pkt.Layer(layers.LayerTypeDot1Q)
1218 if dot1ql != nil {
1219 dot1q := dot1ql.(*layers.Dot1Q)
1220 priority = dot1q.Priority
1221 dropEligible = dot1q.DropEligible
1222 }
1223
1224 pktInnerlan, pktOuterlan := GetVlansFromPacket(pkt)
1225 vpvList, clientMac, err := GetVnetForV6Nni(dhcp6, pktInnerlan, pktOuterlan, priority, eth.DstMAC)
1226 if len(vpvList) == 0 {
1227 logger.Warnw(ctx, "VNET couldn't be found for NNI", log.Fields{"Reason": err})
1228 return
1229 }
1230
1231 ipv6Addr, leaseTime := GetIpv6Addr(dhcp6)
1232
1233 for _, vpv := range vpvList {
Naveen Sampath04696f72022-06-13 15:19:14 +05301234 dsPbit = vpv.GetRemarkedPriority(priority)
1235 // Raise DHCPv6 Reply indication
1236 if vpv.DhcpRelay {
1237 // Inform dhcp response information to dhcp server handler
1238 dhcpResponseReceived(uint16(vpv.CVlan), uint16(vpv.SVlan))
1239
1240 if dhcp6.MsgType == layers.DHCPv6MsgTypeReply && ipv6Addr != nil {
1241 // separate go rotuine is spawned to avoid drop of ACK packet
1242 // as HSIA flows will be deleted if new MAC is learnt.
1243 if len(vpvList) == 1 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301244 go vpv.SetMacAddr(cntx, clientMac)
Naveen Sampath04696f72022-06-13 15:19:14 +05301245 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301246 vpv.Dhcpv6ResultInd(cntx, ipv6Addr, leaseTime)
Naveen Sampath04696f72022-06-13 15:19:14 +05301247 }
1248 raiseDHCPv6Indication(dhcp6.MsgType, vpv, clientMac, ipv6Addr, dsPbit, device, leaseTime)
1249 }
1250
1251 //Replace dst Port value to 546
1252 udp.DstPort = 546
1253 logger.Infow(ctx, "Packet Out UDP Port..", log.Fields{"UDP": udp, "Port": udp.DstPort})
1254
1255 // Create the buffer and the encode options for the outgoing packet
1256 buff := gopacket.NewSerializeBuffer()
1257 if err := udp.SetNetworkLayerForChecksum(ip); err != nil {
1258 logger.Error(ctx, "Error in setting checksum")
1259 return
1260 }
1261 opts := gopacket.SerializeOptions{
1262 FixLengths: true,
1263 ComputeChecksums: true,
1264 }
1265
1266 cTagType := layers.EthernetTypeIPv6
1267 eth.EthernetType = layers.EthernetTypeDot1Q
1268
1269 var pktLayers []gopacket.SerializableLayer
1270 pktLayers = append(pktLayers, eth)
1271
1272 var qVlans []of.VlanType
1273 var qVlanLayers []gopacket.SerializableLayer
1274
1275 if vpv.AllowTransparent {
1276 vlanThreshold := 2
1277 // In case of ONU_CVLAN or OLT_SVLAN, the DS pkts have single configured vlan
1278 // In case of ONU_CVLAN_OLT_SVLAN or OLT_CVLAN_OLT_SVLAN, the DS pkts have 2 configured vlan
1279 // Based on that, the no. of vlans should be ignored to get only transparent vlans
1280 if vpv.VlanControl == ONUCVlan || vpv.VlanControl == OLTSVlan || vpv.VlanControl == None {
1281 vlanThreshold = 1
1282 }
1283 nxtLayer := layers.EthernetTypeDot1Q
1284 if vlans := GetVlans(pkt); len(vlans) > vlanThreshold {
1285 qVlans = vlans[vlanThreshold:]
1286 cTagType = layers.EthernetTypeDot1Q
1287 }
1288 for i, qVlan := range qVlans {
1289 vlan := uint16(qVlan)
1290 if i == (len(qVlans) - 1) {
1291 nxtLayer = layers.EthernetTypeIPv6
1292 }
1293 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
1294 qVlanLayers = append(qVlanLayers, qdot1q)
1295 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301296 }
1297 switch vpv.VlanControl {
1298 case ONUCVlanOLTSVlan:
1299 cdot1q := &layers.Dot1Q{Priority: dsPbit, VLANIdentifier: uint16(vpv.CVlan), DropEligible: dropEligible, Type: cTagType}
1300 pktLayers = append(pktLayers, cdot1q)
1301 case ONUCVlan,
1302 None:
1303 sdot1q := &layers.Dot1Q{Priority: dsPbit, VLANIdentifier: uint16(vpv.SVlan), DropEligible: dropEligible, Type: cTagType}
1304 pktLayers = append(pktLayers, sdot1q)
1305 case OLTCVlanOLTSVlan,
1306 OLTSVlan:
1307 udot1q := &layers.Dot1Q{Priority: dsPbit, VLANIdentifier: uint16(vpv.UniVlan), DropEligible: dropEligible, Type: cTagType}
1308 pktLayers = append(pktLayers, udot1q)
1309 default:
1310 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
1311 }
1312
1313 pktLayers = append(pktLayers, qVlanLayers...)
1314 pktLayers = append(pktLayers, ip)
1315 pktLayers = append(pktLayers, udp)
1316 pktLayers = append(pktLayers, dhcp6)
1317 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
1318 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
1319 logger.Errorw(ctx, "Packet Serialization Failed", log.Fields{"Reason": err.Error()})
1320 return
1321 }
1322
1323 if err := cntlr.GetController().PacketOutReq(device, vpv.Port, port, buff.Bytes(), false); err != nil {
1324 logger.Errorw(ctx, "PacketOutReq Failed", log.Fields{"Reason": err.Error()})
1325 }
1326 }
1327}
1328
1329// The DHCP relay application is maintained within the structures below
1330var dhcpNws *DhcpNetworks
1331
1332func init() {
1333 dhcpNws = NewDhcpNetworks()
1334}
Tinoj Josephec742f62022-09-29 19:11:10 +05301335
1336type DhcpAllocation struct {
Akash Sonib3abf522022-12-19 13:20:02 +05301337 SubscriberID string `json:"subscriberId"`
1338 ConnectPoint string `json:"connectPoint"`
vinokuma926cb3e2023-03-29 11:41:06 +05301339 AllocationTimeStamp time.Time `json:"allocationTimestamp"`
Akash Sonib3abf522022-12-19 13:20:02 +05301340 MacAddress net.HardwareAddr `json:"macAddress"`
vinokuma926cb3e2023-03-29 11:41:06 +05301341 CircuitID []byte `json:"circuitId"`
1342 IPAllocated net.IP `json:"ipAllocated"`
Akash Sonib3abf522022-12-19 13:20:02 +05301343 State int `json:"state"`
1344 VlanID int `json:"vlanId"`
Tinoj Josephec742f62022-09-29 19:11:10 +05301345}
1346
1347// GetAllocations returns DhcpAllocation info for all devices or for a device ID
Akash Sonib3abf522022-12-19 13:20:02 +05301348func (va *VoltApplication) GetAllocations(cntx context.Context, deviceID string) ([]DhcpAllocation, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05301349 logger.Debugw(ctx, "GetAllocations", log.Fields{"DeviceID": deviceID})
Akash Sonib3abf522022-12-19 13:20:02 +05301350 allocations := []DhcpAllocation{}
Tinoj Josephec742f62022-09-29 19:11:10 +05301351 for _, drv := range dhcpNws.Networks {
1352 drv.sessionLock.RLock()
1353 for _, session := range drv.sessions {
1354 vpv, ok := session.(*VoltPortVnet)
1355 if ok {
1356 var subscriber string
1357 // return Name of first service
1358 vpv.services.Range(func(key, value interface{}) bool {
1359 svc := value.(*VoltService)
1360 subscriber = svc.Name
1361 return false
1362 })
1363 // If deviceID is not provided, return all allocations
1364 // If deviceID exists then filter on deviceID
1365 if len(deviceID) == 0 || deviceID == vpv.Device {
Akash Sonib3abf522022-12-19 13:20:02 +05301366 allocation := DhcpAllocation{
1367 SubscriberID: subscriber,
1368 ConnectPoint: vpv.Device,
1369 MacAddress: vpv.MacAddr,
1370 State: int(vpv.RelayState),
1371 VlanID: int(vpv.SVlan),
1372 CircuitID: vpv.CircuitID,
vinokuma926cb3e2023-03-29 11:41:06 +05301373 IPAllocated: vpv.Ipv4Addr,
Akash Sonib3abf522022-12-19 13:20:02 +05301374 AllocationTimeStamp: vpv.DhcpExpiryTime,
1375 }
Tinoj Josephec742f62022-09-29 19:11:10 +05301376 logger.Debugw(ctx, "DHCP Allocation found", log.Fields{"DhcpAlloc": allocation})
1377 allocations = append(allocations, allocation)
1378 }
1379 }
1380 }
1381 drv.sessionLock.RUnlock()
1382 }
1383 return allocations, nil
1384}
Akash Sonib3abf522022-12-19 13:20:02 +05301385
1386type MacLearnerInfo struct {
vinokuma926cb3e2023-03-29 11:41:06 +05301387 DeviceID string `json:"deviceId"`
Akash Sonib3abf522022-12-19 13:20:02 +05301388 PortNumber string `json:"portNumber"`
vinokuma926cb3e2023-03-29 11:41:06 +05301389 VlanID string `json:"vlanId"`
Akash Sonib3abf522022-12-19 13:20:02 +05301390 MacAddress string `json:"macAddress"`
1391}
1392
1393func (va *VoltApplication) GetAllMacLearnerInfo() ([]MacLearnerInfo, error) {
1394 logger.Info(ctx, "GetMacLearnerInfo")
1395 macLearner := []MacLearnerInfo{}
1396 for _, drv := range dhcpNws.Networks {
1397 logger.Debugw(ctx, "drv found", log.Fields{"drv": drv})
1398 drv.sessionLock.RLock()
1399 for _, session := range drv.sessions {
1400 vpv, ok := session.(*VoltPortVnet)
1401 if ok {
1402 macLearn := MacLearnerInfo{
vinokuma926cb3e2023-03-29 11:41:06 +05301403 DeviceID: vpv.Device,
Akash Sonib3abf522022-12-19 13:20:02 +05301404 PortNumber: vpv.Port,
vinokuma926cb3e2023-03-29 11:41:06 +05301405 VlanID: vpv.SVlan.String(),
Akash Sonib3abf522022-12-19 13:20:02 +05301406 MacAddress: vpv.MacAddr.String(),
1407 }
1408 logger.Debugw(ctx, "MacLerner found", log.Fields{"MacLearn": macLearn})
1409 macLearner = append(macLearner, macLearn)
1410 }
1411 }
1412 drv.sessionLock.RUnlock()
1413 }
1414 return macLearner, nil
1415}
1416
vinokuma926cb3e2023-03-29 11:41:06 +05301417func (va *VoltApplication) GetMacLearnerInfo(cntx context.Context, deviceID, portNumber, vlanID string) (MacLearnerInfo, error) {
Akash Sonib3abf522022-12-19 13:20:02 +05301418 logger.Info(ctx, "GetMecLearnerInfo")
1419 macLearn := MacLearnerInfo{}
1420 for _, drv := range dhcpNws.Networks {
1421 logger.Infow(ctx, "drv found", log.Fields{"drv": drv})
1422 drv.sessionLock.RLock()
1423 for _, session := range drv.sessions {
1424 vpv, ok := session.(*VoltPortVnet)
1425 if ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301426 if deviceID == vpv.Device && portNumber == vpv.Port && vlanID == vpv.SVlan.String() {
Akash Sonib3abf522022-12-19 13:20:02 +05301427 macLearn = MacLearnerInfo{
vinokuma926cb3e2023-03-29 11:41:06 +05301428 DeviceID: vpv.Device,
Akash Sonib3abf522022-12-19 13:20:02 +05301429 PortNumber: vpv.Port,
vinokuma926cb3e2023-03-29 11:41:06 +05301430 VlanID: vpv.SVlan.String(),
Akash Sonib3abf522022-12-19 13:20:02 +05301431 MacAddress: vpv.MacAddr.String(),
1432 }
1433 logger.Infow(ctx, "MacLerner found", log.Fields{"MacLearn": macLearn})
vinokuma926cb3e2023-03-29 11:41:06 +05301434 } else if deviceID == vpv.Device && portNumber == vpv.Port && vlanID == "" {
Akash Sonib3abf522022-12-19 13:20:02 +05301435 macLearn = MacLearnerInfo{
vinokuma926cb3e2023-03-29 11:41:06 +05301436 DeviceID: vpv.Device,
Akash Sonib3abf522022-12-19 13:20:02 +05301437 PortNumber: vpv.Port,
vinokuma926cb3e2023-03-29 11:41:06 +05301438 VlanID: vpv.SVlan.String(),
Akash Sonib3abf522022-12-19 13:20:02 +05301439 MacAddress: vpv.MacAddr.String(),
1440 }
1441 logger.Infow(ctx, "MacLerner found", log.Fields{"MacLearn": macLearn})
1442 }
1443 }
1444 }
1445 drv.sessionLock.RUnlock()
1446 }
1447 return macLearn, nil
1448}
1449
1450func (va *VoltApplication) GetIgnoredPorts() (map[string][]string, error) {
1451 logger.Info(ctx, "GetIgnoredPorts")
1452 IgnoredPorts := make(map[string][]string)
1453 portIgnored := func(key, value interface{}) bool {
1454 voltDevice := value.(*VoltDevice)
1455 logger.Infow(ctx, "Inside GetIgnoredPorts method", log.Fields{"deviceName": voltDevice.Name})
1456 voltDevice.Ports.Range(func(key, value interface{}) bool {
1457 port := key.(string)
1458 logger.Infow(ctx, "Inside GetIgnoredPorts method", log.Fields{"port": port})
1459 //Obtain all VPVs associated with the port
1460 vnets, ok := GetApplication().VnetsByPort.Load(port)
1461 if !ok {
1462 return true
1463 }
1464 for _, vpv := range vnets.([]*VoltPortVnet) {
Akash Sonib3abf522022-12-19 13:20:02 +05301465 if vpv.MacLearning == MacLearningNone {
1466 IgnoredPorts[vpv.Device] = append(IgnoredPorts[vpv.Device], vpv.Port)
1467 }
1468 }
1469 logger.Debugw(ctx, "Ignored Port", log.Fields{"Ignored Port": IgnoredPorts})
1470 return true
1471 })
1472 return true
1473 }
1474 va.DevicesDisc.Range(portIgnored)
1475 logger.Info(ctx, "GetIgnoredPorts completed")
1476 return IgnoredPorts, nil
1477}