blob: 8b627600d052cfa7a330c80f5947b4d0b9d7ee9d [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.
vinokuma926cb3e2023-03-29 11:41:06 +053014 */
Naveen Sampath04696f72022-06-13 15:19:14 +053015
16package application
17
18import (
19 "context"
20 "errors"
21 "net"
22 "time"
23
24 "github.com/google/gopacket"
25 "github.com/google/gopacket/layers"
26
27 cntlr "voltha-go-controller/internal/pkg/controller"
28 "voltha-go-controller/internal/pkg/of"
29 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053030 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053031)
32
33// PppoeIaState type
34type PppoeIaState uint8
35
36const (
37 // PppoeIaStateNone constant
38 PppoeIaStateNone PppoeIaState = iota
39 // PppoeIaStatePADI constant
40 PppoeIaStatePADI
41 // PppoeIaStatePADO constant
42 PppoeIaStatePADO
43 // PppoeIaStatePADR constant
44 PppoeIaStatePADR
45 // PppoeIaStatePADS constant
46 PppoeIaStatePADS
47 // PppoeIaStatePADT constant
48 PppoeIaStatePADT
49)
50
51const (
52 // PPPoEVendorID constant
53 PPPoEVendorID uint32 = 0x0DE9
54 // TYPECIRCUITID constant
55 TYPECIRCUITID byte = 0x01
56 // TYPEREMOTEID constant
57 TYPEREMOTEID byte = 0x02
58 // TYPEMINDATAUS constant
59 TYPEMINDATAUS byte = 0x83
60 // TYPEMINDATADS constant
61 TYPEMINDATADS byte = 0x84
62 // TYPEMAXDATAUS constant
63 TYPEMAXDATAUS byte = 0x87
64 // TYPEMAXDATADS constant
65 TYPEMAXDATADS byte = 0x88
66)
67
68var (
69 // DSLATTRVendorID is PPPoEVendorID in byte format
70 DSLATTRVendorID = util.Uint32ToByte(PPPoEVendorID)
71)
72
73// IPppoeIaSession interface
74type IPppoeIaSession interface {
75 GetCircuitID() []byte
76 GetRemoteID() []byte
77 GetNniVlans() (uint16, uint16)
78 GetPppoeIaState() PppoeIaState
79 SetPppoeIaState(PppoeIaState)
Tinoj Joseph07cc5372022-07-18 22:53:51 +053080 SetMacAddr(context.Context, net.HardwareAddr)
Naveen Sampath04696f72022-06-13 15:19:14 +053081}
82
83// PppoeIaRelayVnet : The PppoeIa relay sessions are stored in a map to be retrieved from when
84// a response is received from the network. The map uses the VLANs and the
85// the MAC address as key to finding the service
86// PppoeIa Relay Virtual Network hosts a set of PppoeIa relay sessions that belong
87// to the network. It supports two VLANs as its identify. If a single VLAN or
88// no VLAN is to be used, those two should be passed as 4096 (VlanNone)
89type PppoeIaRelayVnet struct {
vinokuma926cb3e2023-03-29 11:41:06 +053090 sessions *util.ConcurrentMap //map[[6]byte]IPppoeIaSession
Naveen Sampath04696f72022-06-13 15:19:14 +053091 OuterVlan uint16
92 InnerVlan uint16
Naveen Sampath04696f72022-06-13 15:19:14 +053093}
94
95// PppoeIaNetworks : PppoeIa Networks hosts different PppoeIa networks that in turn hold the PppoeIa
96// sessions
97type PppoeIaNetworks struct {
98 Networks *util.ConcurrentMap //map[uint32]*PppoeIaRelayVnet
99}
100
101// NewPppoeIaRelayVnet is constructor for a PppoeIa Relay Virtual network
102func NewPppoeIaRelayVnet(outerVlan uint16, innerVlan uint16) *PppoeIaRelayVnet {
103 var drv PppoeIaRelayVnet
104
105 drv.OuterVlan = outerVlan
106 drv.InnerVlan = innerVlan
107 drv.sessions = util.NewConcurrentMap() //make(map[[6]byte]IPppoeIaSession)
108 return &drv
109}
110
111// AddPppoeIaRelayVnet add pppoeia relay vnet
112func (dn *PppoeIaNetworks) AddPppoeIaRelayVnet(outerVlan uint16, innerVlan uint16) *PppoeIaRelayVnet {
113 comboVlan := uint32(outerVlan)<<16 + uint32(innerVlan)
114 if drv, ok := dn.Networks.Get(comboVlan); ok {
115 return drv.(*PppoeIaRelayVnet)
116 }
117 drv := NewPppoeIaRelayVnet(outerVlan, innerVlan)
118 dn.Networks.Set(comboVlan, drv)
119 return drv
120}
121
122// NewPppoeIaNetworks is constructor for PppoeIa network
123func NewPppoeIaNetworks() *PppoeIaNetworks {
124 var dn PppoeIaNetworks
125 dn.Networks = util.NewConcurrentMap() //make(map[uint32]*PppoeIaRelayVnet)
126 return &dn
127}
128
129// AddPppoeIaSession to add pppoeia session
130func (dn *PppoeIaNetworks) AddPppoeIaSession(pkt gopacket.Packet, session IPppoeIaSession) {
131 var key [6]byte
132 ethl := pkt.Layer(layers.LayerTypeEthernet)
133 eth, _ := ethl.(*layers.Ethernet)
134 addr := eth.SrcMAC
135 copy(key[:], addr[0:6])
136 drv := dn.AddPppoeIaRelayVnet(session.GetNniVlans())
137 drv.sessions.Set(key, session)
138}
139
140// DelPppoeIaSession to delete pppoeia session
141func (dn *PppoeIaNetworks) DelPppoeIaSession(pkt gopacket.Packet, session IPppoeIaSession) {
142 var key [6]byte
143 ethl := pkt.Layer(layers.LayerTypeEthernet)
144 eth, _ := ethl.(*layers.Ethernet)
145 addr := eth.SrcMAC
146 if len(addr) != 6 {
147 logger.Errorw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
148 return
149 }
150 copy(key[:], addr[0:6])
151 drv := dn.AddPppoeIaRelayVnet(session.GetNniVlans())
152 drv.sessions.Remove(key)
153}
154
155// delPppoeIaSessions to delete pppoeia sessions
156func delPppoeIaSessions(addr net.HardwareAddr, outervlan of.VlanType, innervlan of.VlanType) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530157 var key [6]byte
158 if addr == nil || !NonZeroMacAddress(addr) {
159 logger.Warnw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
160 return
161 }
162 copy(key[:], addr[0:6])
163 drv := pppoeIaNws.AddPppoeIaRelayVnet(uint16(outervlan), uint16(innervlan))
164 drv.sessions.Remove(key)
165 logger.Infow(ctx, "PppoeIa Sessions deleted", log.Fields{"MAC": addr})
166}
167
168// GetPppoeIaSession to get pppoeia sessions
169func (dn *PppoeIaNetworks) GetPppoeIaSession(outerVlan uint16, innerVlan uint16, addr net.HardwareAddr) (IPppoeIaSession, error) {
170 var key [6]byte
171 if len(addr) != 6 {
172 logger.Errorw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
173 return nil, errors.New("Invalid MAC address")
174 }
175 copy(key[:], addr[0:6])
176 drv := dn.AddPppoeIaRelayVnet(outerVlan, innerVlan)
177 logger.Infow(ctx, "Key for PPPoE session", log.Fields{"Key": key})
178 if session, ok := drv.sessions.Get(key); ok {
179 return session.(IPppoeIaSession), nil
180 }
181 return nil, ErrSessionDoNotExist
182}
183
184// GetVnetForNni to get vnet for nni port
185func GetVnetForNni(addr net.HardwareAddr, cvlan of.VlanType, svlan of.VlanType, pbit uint8) (*VoltPortVnet, error) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530186 var err error
187 var session IPppoeIaSession
188 logger.Infow(ctx, "Mac Obtained MAC: ", log.Fields{"Addr": addr})
189 if session, err = pppoeIaNws.GetPppoeIaSession(uint16(svlan), uint16(cvlan), addr); err != nil {
190 logger.Errorw(ctx, "PPPoE Session retrieval failed", log.Fields{"Error": err})
191 if err == ErrSessionDoNotExist {
192 logger.Info(ctx, "Finding matching VPV from packet")
193 vpvs, err1 := GetApplication().GetVpvsForDsPkt(cvlan, svlan, addr, pbit)
194 if len(vpvs) == 1 {
195 return vpvs[0], nil
196 }
197 return nil, err1
198 }
199 return nil, err
200 }
201
202 if session != nil {
203 vpv, ok := session.(*VoltPortVnet)
204
205 if ok {
206 logger.Infow(ctx, "Session Exist: VPV found", log.Fields{"VPV": vpv})
207 return vpv, nil
208 }
209 }
210 logger.Error(ctx, "PPPoE Session retrieved of wrong type")
211 return nil, errors.New("The session retrieved of wrong type")
212}
213
214// AddIaOption : Addition of PppoeIa Option 82 which codes circuit-id and remote-id
215// into the packet. This happens as the request is relayed to the
216// PppoeIa servers on the NNI
217func AddIaOption(svc *VoltService, pppoe *layers.PPPoE) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530218 //NOTE : both cID and rID should not be empty if this function is called
219 var data []byte
220 cID := svc.GetCircuitID()
221 rID := svc.RemoteID
222
223 if len(cID) != 0 || len(rID) != 0 || svc.isDataRateAttrPresent() {
224 data = append(data, DSLATTRVendorID...)
225 }
226
227 logger.Debugw(ctx, "Vendor Info", log.Fields{"Data": data})
228
229 if len(cID) != 0 {
230 data = append(data, TYPECIRCUITID)
231 data = append(data, byte(len(cID)))
232 data = append(data, cID...)
233 }
234 if len(rID) != 0 {
235 data = append(data, TYPEREMOTEID)
236 data = append(data, byte(len(rID)))
237 data = append(data, rID...)
238 }
239
240 if svc.isDataRateAttrPresent() {
241 minDrUs := util.Uint32ToByte(svc.MinDataRateUs)
242 data = append(data, TYPEMINDATAUS)
243 data = append(data, byte(len(minDrUs)))
244 data = append(data, minDrUs...)
245
246 minDrDs := util.Uint32ToByte(svc.MinDataRateDs)
247 data = append(data, TYPEMINDATADS)
248 data = append(data, byte(len(minDrDs)))
249 data = append(data, minDrDs...)
250
251 maxDrUs := util.Uint32ToByte(svc.MaxDataRateUs)
252 data = append(data, TYPEMAXDATAUS)
253 data = append(data, byte(len(maxDrUs)))
254 data = append(data, maxDrUs...)
255
256 maxDrDs := util.Uint32ToByte(svc.MaxDataRateDs)
257 data = append(data, TYPEMAXDATADS)
258 data = append(data, byte(len(maxDrDs)))
259 data = append(data, maxDrDs...)
260 }
261 option := layers.NewPPPoEOption(layers.PPPoEOptVendorSpecific, data)
262 pppoe.Options = append(pppoe.Options, option)
263}
264
265// DelIaOption for deletion of IA option from the packet received on the NNI interface.
266func DelIaOption(pppoe *layers.PPPoE) {
267 for index, option := range pppoe.Options {
268 if option.Type == layers.PPPoEOptVendorSpecific {
269 pppoe.Options = append(pppoe.Options[0:index], pppoe.Options[index+1:]...)
270 return
271 }
272 }
273}
274
275// ProcessDsPppoeIaPacket : This function processes DS PppoeIa packet received on the NNI port.
276// The services are attached to the access ports. Thus, the PppoeIa
277// session is derived from the list of PppoeIa sessions stored in the
278// common map. The key for retrieval includes the VLAN tags in the
279// the packet and the MAC address of the client.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530280func (va *VoltApplication) ProcessDsPppoeIaPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530281 // Retrieve the layers to build the outgoing packet. It is not
282 // possible to add/remove layers to the existing packet and thus
283 // the lyayers are extracted to build the outgoing packet
284 eth := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
285 pppoe := pkt.Layer(layers.LayerTypePPPoE).(*layers.PPPoE)
286
287 logger.Infow(ctx, "Processing Southbound DS PppoeIa packet", log.Fields{"Port": port, "Type": pppoe.Code})
288
289 // Retrieve the priority and drop eligible flags from the
290 // packet received
291 var priority uint8
292 var dropEligible bool
293 dot1ql := pkt.Layer(layers.LayerTypeDot1Q)
294 if dot1ql != nil {
295 dot1q := dot1ql.(*layers.Dot1Q)
296 priority = dot1q.Priority
297 dropEligible = dot1q.DropEligible
298 }
299
300 pktInnerlan, pktOuterlan := GetVlansFromPacket(pkt)
301 vpv, err := GetVnetForNni(eth.DstMAC, pktInnerlan, pktOuterlan, priority)
302 if err != nil {
303 logger.Errorw(ctx, "VNET couldn't be found for NNI", log.Fields{"Error": err})
304 return
305 }
306
307 // Do not modify pppoe header if vnet's mac_learning type is not PPPoE-IA.
308 if vpv.PppoeIa {
309 // Delete the IA option that may be included in the response
310 DelIaOption(pppoe)
311 if pppoe.Code == layers.PPPoECodePADO {
312 vpv.SetPppoeIaState(PppoeIaStatePADO)
313 } else if pppoe.Code == layers.PPPoECodePADS {
314 vpv.SetPppoeIaState(PppoeIaStatePADS)
315 } else if pppoe.Code == layers.PPPoECodePADT {
316 vpv.SetPppoeIaState(PppoeIaStatePADT)
317 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530318 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530319 }
320 // Create the outgoing bufer and set the checksum in the packet
321 buff := gopacket.NewSerializeBuffer()
322 opts := gopacket.SerializeOptions{
323 FixLengths: true,
324 ComputeChecksums: true,
325 }
326
327 cTagType := layers.EthernetTypePPPoEDiscovery
328 eth.EthernetType = layers.EthernetTypeDot1Q
329 priority = vpv.GetRemarkedPriority(priority)
330
331 var pktLayers []gopacket.SerializableLayer
332 pktLayers = append(pktLayers, eth)
333
334 var qVlans []of.VlanType
335 var qVlanLayers []gopacket.SerializableLayer
336
337 if vpv.AllowTransparent {
338 vlanThreshold := 2
339 // In case of ONU_CVLAN or OLT_SVLAN, the DS pkts have single configured vlan
340 // In case of ONU_CVLAN_OLT_SVLAN or OLT_CVLAN_OLT_SVLAN, the DS pkts have 2 configured vlan
341 // Based on that, the no. of vlans should be ignored to get only transparent vlans
342 if vpv.VlanControl == ONUCVlan || vpv.VlanControl == OLTSVlan || vpv.VlanControl == None {
343 vlanThreshold = 1
344 }
345 nxtLayer := layers.EthernetTypeDot1Q
346 if vlans := GetVlans(pkt); len(vlans) > vlanThreshold {
347 qVlans = vlans[vlanThreshold:]
348 cTagType = layers.EthernetTypeDot1Q
349 }
350 for i, qVlan := range qVlans {
351 vlan := uint16(qVlan)
352 if i == (len(qVlans) - 1) {
353 nxtLayer = layers.EthernetTypePPPoEDiscovery
354 }
355 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
356 qVlanLayers = append(qVlanLayers, qdot1q)
357 }
358 }
359
360 switch vpv.VlanControl {
361 case ONUCVlanOLTSVlan:
362 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.CVlan), DropEligible: dropEligible, Type: cTagType}
363 pktLayers = append(pktLayers, cdot1q)
364 case ONUCVlan,
365 None:
366 sdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.SVlan), DropEligible: dropEligible, Type: cTagType}
367 pktLayers = append(pktLayers, sdot1q)
368 case OLTCVlanOLTSVlan,
369 OLTSVlan:
370 udot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.UniVlan), DropEligible: dropEligible, Type: cTagType}
371 pktLayers = append(pktLayers, udot1q)
372 default:
373 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
374 return
375 }
376
377 pktLayers = append(pktLayers, qVlanLayers...)
378 pktLayers = append(pktLayers, pppoe)
379
380 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
381 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
382 logger.Errorw(ctx, "Packet Serialization Failed", log.Fields{"Reason": err.Error()})
383 return
384 }
385
386 if err := cntlr.GetController().PacketOutReq(device, vpv.Port, port, buff.Bytes(), false); err != nil {
387 logger.Warnw(ctx, "PacketOutReq Failed", log.Fields{"Device": device, "Error": err})
388 }
389}
390
391// ProcessUsPppoeIaPacket : The US PppoeIa packet is identified the PppoeIa OP in the packet. A request is considered upstream
392// and the service associated with the packet is located by the port and VLANs in the packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530393func (va *VoltApplication) ProcessUsPppoeIaPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530394 // We received the packet on an access port and the service for the packet can be
395 // gotten from the port and the packet
396 vpv, svc := va.GetVnetFromPkt(device, port, pkt)
397 if vpv == nil {
398 logger.Errorw(ctx, "VNET couldn't be found from packet", log.Fields{"Device": device, "Port": port})
399 return
400 }
401
402 outport, _ := va.GetNniPort(device)
403 if outport == "" || outport == "0" {
404 logger.Errorw(ctx, "NNI Port not found for device. Dropping Packet", log.Fields{"NNI": outport})
405 return
406 }
407
408 //Add PPPoE session for reference so that the DS pkts can be processed and re-directed
409 pppoeIaNws.AddPppoeIaSession(pkt, vpv)
410
411 // Extract the layers in the packet to prepare the outgoing packet
412 // We use the layers to build the outgoing packet from scratch as
413 // the packet received can't be modified to add/remove layers
414 eth := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
415 pppoe := pkt.Layer(layers.LayerTypePPPoE).(*layers.PPPoE)
416 msgType := pppoe.Code
417 logger.Infow(ctx, "Processing Southbound US PppoeIa packet", log.Fields{"Device": device, "Port": port, "Type": pppoe.Code})
418
419 AddIaOption(svc, pppoe)
420
421 // Learn the 8021P values from the packet received
422 var priority uint8
423 dropEligible := false
424 dot1ql := pkt.Layer(layers.LayerTypeDot1Q)
425 if dot1ql != nil {
426 dot1q := dot1ql.(*layers.Dot1Q)
427 priority = dot1q.Priority
428 dropEligible = dot1q.DropEligible
429 }
430
431 if vpv.PppoeIa {
vinokuma926cb3e2023-03-29 11:41:06 +0530432 // Maintain the session MAC as learnt MAC, since MAC is required for deletion of PPPoE session
Naveen Sampath04696f72022-06-13 15:19:14 +0530433 if msgType == layers.PPPoECodePADI || msgType == layers.PPPoECodePADR {
434 if !util.MacAddrsMatch(vpv.MacAddr, eth.SrcMAC) {
435 expectedPort := va.GetMacInPortMap(eth.SrcMAC)
436 if expectedPort != "" && expectedPort != vpv.Port {
437 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-pppoe-message",
438 log.Fields{"MsgType": msgType, "ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": eth.SrcMAC.String()})
439 return
440 }
441 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530442 vpv.SetMacAddr(cntx, eth.SrcMAC)
Naveen Sampath04696f72022-06-13 15:19:14 +0530443 }
444
445 if pppoe.Code == layers.PPPoECodePADI {
446 vpv.SetPppoeIaState(PppoeIaStatePADI)
447 } else if pppoe.Code == layers.PPPoECodePADR {
448 vpv.SetPppoeIaState(PppoeIaStatePADR)
449 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530450 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530451 }
452
453 buff := gopacket.NewSerializeBuffer()
454 opts := gopacket.SerializeOptions{
455 FixLengths: true,
456 ComputeChecksums: true,
457 }
458
459 cTagType := layers.EthernetTypePPPoEDiscovery
460 outerVlan, innerVlan := vpv.GetNniVlans()
461 logger.Debugw(ctx, "Vnet Vlans", log.Fields{"Svlan": outerVlan, "Cvlan": innerVlan})
462 eth.EthernetType = vpv.SVlanTpid
463
464 var pktLayers []gopacket.SerializableLayer
465 pktLayers = append(pktLayers, eth)
466
467 var qVlans []of.VlanType
468 var qVlanLayers []gopacket.SerializableLayer
469
470 if vpv.AllowTransparent {
471 nxtLayer := layers.EthernetTypeDot1Q
472 if vlans := GetVlans(pkt); len(vlans) > 1 {
473 qVlans = vlans[1:]
474 logger.Debugw(ctx, "Q Vlans", log.Fields{"Vlan List": qVlans})
475 cTagType = layers.EthernetTypeDot1Q
476 }
477 for i, qVlan := range qVlans {
478 vlan := uint16(qVlan)
479 if i == (len(qVlans) - 1) {
480 nxtLayer = layers.EthernetTypePPPoEDiscovery
481 }
482 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
483 qVlanLayers = append(qVlanLayers, qdot1q)
484 }
485 }
486
487 switch vpv.VlanControl {
488 case ONUCVlanOLTSVlan,
489 OLTCVlanOLTSVlan:
490 sdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: layers.EthernetTypeDot1Q}
491 pktLayers = append(pktLayers, sdot1q)
492 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: innerVlan, DropEligible: dropEligible, Type: cTagType}
493 pktLayers = append(pktLayers, cdot1q)
494 case ONUCVlan,
495 OLTSVlan,
496 None:
497 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: cTagType}
498 pktLayers = append(pktLayers, cdot1q)
499 default:
500 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
501 return
502 }
503
504 pktLayers = append(pktLayers, qVlanLayers...)
505 pktLayers = append(pktLayers, pppoe)
506 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
507 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
508 return
509 }
510
511 // Now the packet constructed is output towards the switch to be emitted on
512 // the NNI port
513 if err := cntlr.GetController().PacketOutReq(device, outport, port, buff.Bytes(), false); err != nil {
514 logger.Warnw(ctx, "PacketOutReq Failed", log.Fields{"Device": device, "Error": err})
515 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530516}
517
518// ProcessPPPoEIaPacket to process Pppoeia packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530519func (va *VoltApplication) ProcessPPPoEIaPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530520 // Make some error checks before proceeding
521 pppoel := pkt.Layer(layers.LayerTypePPPoE)
522 if pppoel == nil {
523 return
524 }
525 _, ok := pppoel.(*layers.PPPoE)
526 if !ok {
527 return
528 }
529
530 // Let us assess the direction of the packet. We can do so by the port
531 // which is more reliable or do by the PPPoE code which is less reliable
532 isUs := true
533 if nni, _ := GetApplication().GetNniPort(device); nni == port {
534 isUs = false
535 }
536
537 // This is a valid PPPoE packet and can be processed
538 if isUs {
539 // This is treated as an upstream packet in the VOLT application
540 // as VOLT serves access subscribers who use DHCP to acquire IP
541 // address and these packets go upstream to the network
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530542 va.ProcessUsPppoeIaPacket(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530543 } else {
544 // This is a downstream packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530545 va.ProcessDsPppoeIaPacket(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530546 }
547}
548
549// ProcessPPPoEPacket to process Pppoe packet
550func (va *VoltApplication) ProcessPPPoEPacket(device string, port string, pkt gopacket.Packet) {
551 dpt := NewPppoeIaPacketTask(pkt, device, port)
552 va.pppoeTasks.AddTask(dpt)
553}
554
555// pppoeIaNws : The DHCP relay application is maintained within the structures below
556var pppoeIaNws *PppoeIaNetworks
557
558func init() {
559 pppoeIaNws = NewPppoeIaNetworks()
560 RegisterPacketHandler(PPPOE, ProcessPPPoEPacket)
561}
562
563// ProcessPPPoEPacket : CallBack function registered with application to handle PPPoE packetIn
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530564func ProcessPPPoEPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530565 GetApplication().ProcessPPPoEPacket(device, port, pkt)
566}
567
568// PppoeIaPacketTask : Task to add or delete flows of a service
569type PppoeIaPacketTask struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530570 ctx context.Context
571 pkt gopacket.Packet
572 device string
573 port string
574 timestamp string
vinokuma926cb3e2023-03-29 11:41:06 +0530575 taskID uint8
Naveen Sampath04696f72022-06-13 15:19:14 +0530576}
577
578// NewPppoeIaPacketTask constructor for PppoeIaPacketTask
579func NewPppoeIaPacketTask(pkt gopacket.Packet, dev string, port string) *PppoeIaPacketTask {
580 var dpt PppoeIaPacketTask
581 dpt.pkt = pkt
582 dpt.device = dev
583 dpt.port = port
584 dpt.timestamp = (time.Now()).Format(time.RFC3339Nano)
585 return &dpt
586}
587
588// Name to return name for PppoeIaPacketTask
589func (dpt *PppoeIaPacketTask) Name() string {
590 return "DHCP Packet Task"
591}
592
593// TaskID to return task id for PppoeIaPacketTask
594func (dpt *PppoeIaPacketTask) TaskID() uint8 {
595 return dpt.taskID
596}
597
598// Timestamp to return timestamp for PppoeIaPacketTask
599func (dpt *PppoeIaPacketTask) Timestamp() string {
600 return dpt.timestamp
601}
602
603// Stop to stop the PppoeIaPacketTask
604func (dpt *PppoeIaPacketTask) Stop() {
605}
606
607// Start to start PppoeIaPacketTask
608func (dpt *PppoeIaPacketTask) Start(ctx context.Context, taskID uint8) error {
609 dpt.taskID = taskID
610 dpt.ctx = ctx
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530611 GetApplication().ProcessPPPoEIaPacket(ctx, dpt.device, dpt.port, dpt.pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530612 return nil
613}