blob: 2d50033703e4edad87e96c8e0413d99ff9d7bb2f [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 (
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 {
90 OuterVlan uint16
91 InnerVlan uint16
92 sessions *util.ConcurrentMap //map[[6]byte]IPppoeIaSession
93}
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) {
157
158 var key [6]byte
159 if addr == nil || !NonZeroMacAddress(addr) {
160 logger.Warnw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
161 return
162 }
163 copy(key[:], addr[0:6])
164 drv := pppoeIaNws.AddPppoeIaRelayVnet(uint16(outervlan), uint16(innervlan))
165 drv.sessions.Remove(key)
166 logger.Infow(ctx, "PppoeIa Sessions deleted", log.Fields{"MAC": addr})
167}
168
169// GetPppoeIaSession to get pppoeia sessions
170func (dn *PppoeIaNetworks) GetPppoeIaSession(outerVlan uint16, innerVlan uint16, addr net.HardwareAddr) (IPppoeIaSession, error) {
171 var key [6]byte
172 if len(addr) != 6 {
173 logger.Errorw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
174 return nil, errors.New("Invalid MAC address")
175 }
176 copy(key[:], addr[0:6])
177 drv := dn.AddPppoeIaRelayVnet(outerVlan, innerVlan)
178 logger.Infow(ctx, "Key for PPPoE session", log.Fields{"Key": key})
179 if session, ok := drv.sessions.Get(key); ok {
180 return session.(IPppoeIaSession), nil
181 }
182 return nil, ErrSessionDoNotExist
183}
184
185// GetVnetForNni to get vnet for nni port
186func GetVnetForNni(addr net.HardwareAddr, cvlan of.VlanType, svlan of.VlanType, pbit uint8) (*VoltPortVnet, error) {
187
188 var err error
189 var session IPppoeIaSession
190 logger.Infow(ctx, "Mac Obtained MAC: ", log.Fields{"Addr": addr})
191 if session, err = pppoeIaNws.GetPppoeIaSession(uint16(svlan), uint16(cvlan), addr); err != nil {
192 logger.Errorw(ctx, "PPPoE Session retrieval failed", log.Fields{"Error": err})
193 if err == ErrSessionDoNotExist {
194 logger.Info(ctx, "Finding matching VPV from packet")
195 vpvs, err1 := GetApplication().GetVpvsForDsPkt(cvlan, svlan, addr, pbit)
196 if len(vpvs) == 1 {
197 return vpvs[0], nil
198 }
199 return nil, err1
200 }
201 return nil, err
202 }
203
204 if session != nil {
205 vpv, ok := session.(*VoltPortVnet)
206
207 if ok {
208 logger.Infow(ctx, "Session Exist: VPV found", log.Fields{"VPV": vpv})
209 return vpv, nil
210 }
211 }
212 logger.Error(ctx, "PPPoE Session retrieved of wrong type")
213 return nil, errors.New("The session retrieved of wrong type")
214}
215
216// AddIaOption : Addition of PppoeIa Option 82 which codes circuit-id and remote-id
217// into the packet. This happens as the request is relayed to the
218// PppoeIa servers on the NNI
219func AddIaOption(svc *VoltService, pppoe *layers.PPPoE) {
220
221 //NOTE : both cID and rID should not be empty if this function is called
222 var data []byte
223 cID := svc.GetCircuitID()
224 rID := svc.RemoteID
225
226 if len(cID) != 0 || len(rID) != 0 || svc.isDataRateAttrPresent() {
227 data = append(data, DSLATTRVendorID...)
228 }
229
230 logger.Debugw(ctx, "Vendor Info", log.Fields{"Data": data})
231
232 if len(cID) != 0 {
233 data = append(data, TYPECIRCUITID)
234 data = append(data, byte(len(cID)))
235 data = append(data, cID...)
236 }
237 if len(rID) != 0 {
238 data = append(data, TYPEREMOTEID)
239 data = append(data, byte(len(rID)))
240 data = append(data, rID...)
241 }
242
243 if svc.isDataRateAttrPresent() {
244 minDrUs := util.Uint32ToByte(svc.MinDataRateUs)
245 data = append(data, TYPEMINDATAUS)
246 data = append(data, byte(len(minDrUs)))
247 data = append(data, minDrUs...)
248
249 minDrDs := util.Uint32ToByte(svc.MinDataRateDs)
250 data = append(data, TYPEMINDATADS)
251 data = append(data, byte(len(minDrDs)))
252 data = append(data, minDrDs...)
253
254 maxDrUs := util.Uint32ToByte(svc.MaxDataRateUs)
255 data = append(data, TYPEMAXDATAUS)
256 data = append(data, byte(len(maxDrUs)))
257 data = append(data, maxDrUs...)
258
259 maxDrDs := util.Uint32ToByte(svc.MaxDataRateDs)
260 data = append(data, TYPEMAXDATADS)
261 data = append(data, byte(len(maxDrDs)))
262 data = append(data, maxDrDs...)
263 }
264 option := layers.NewPPPoEOption(layers.PPPoEOptVendorSpecific, data)
265 pppoe.Options = append(pppoe.Options, option)
266}
267
268// DelIaOption for deletion of IA option from the packet received on the NNI interface.
269func DelIaOption(pppoe *layers.PPPoE) {
270 for index, option := range pppoe.Options {
271 if option.Type == layers.PPPoEOptVendorSpecific {
272 pppoe.Options = append(pppoe.Options[0:index], pppoe.Options[index+1:]...)
273 return
274 }
275 }
276}
277
278// ProcessDsPppoeIaPacket : This function processes DS PppoeIa packet received on the NNI port.
279// The services are attached to the access ports. Thus, the PppoeIa
280// session is derived from the list of PppoeIa sessions stored in the
281// common map. The key for retrieval includes the VLAN tags in the
282// the packet and the MAC address of the client.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530283func (va *VoltApplication) ProcessDsPppoeIaPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530284
285 // Retrieve the layers to build the outgoing packet. It is not
286 // possible to add/remove layers to the existing packet and thus
287 // the lyayers are extracted to build the outgoing packet
288 eth := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
289 pppoe := pkt.Layer(layers.LayerTypePPPoE).(*layers.PPPoE)
290
291 logger.Infow(ctx, "Processing Southbound DS PppoeIa packet", log.Fields{"Port": port, "Type": pppoe.Code})
292
293 // Retrieve the priority and drop eligible flags from the
294 // packet received
295 var priority uint8
296 var dropEligible bool
297 dot1ql := pkt.Layer(layers.LayerTypeDot1Q)
298 if dot1ql != nil {
299 dot1q := dot1ql.(*layers.Dot1Q)
300 priority = dot1q.Priority
301 dropEligible = dot1q.DropEligible
302 }
303
304 pktInnerlan, pktOuterlan := GetVlansFromPacket(pkt)
305 vpv, err := GetVnetForNni(eth.DstMAC, pktInnerlan, pktOuterlan, priority)
306 if err != nil {
307 logger.Errorw(ctx, "VNET couldn't be found for NNI", log.Fields{"Error": err})
308 return
309 }
310
311 // Do not modify pppoe header if vnet's mac_learning type is not PPPoE-IA.
312 if vpv.PppoeIa {
313 // Delete the IA option that may be included in the response
314 DelIaOption(pppoe)
315 if pppoe.Code == layers.PPPoECodePADO {
316 vpv.SetPppoeIaState(PppoeIaStatePADO)
317 } else if pppoe.Code == layers.PPPoECodePADS {
318 vpv.SetPppoeIaState(PppoeIaStatePADS)
319 } else if pppoe.Code == layers.PPPoECodePADT {
320 vpv.SetPppoeIaState(PppoeIaStatePADT)
321 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530322 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530323 }
324 // Create the outgoing bufer and set the checksum in the packet
325 buff := gopacket.NewSerializeBuffer()
326 opts := gopacket.SerializeOptions{
327 FixLengths: true,
328 ComputeChecksums: true,
329 }
330
331 cTagType := layers.EthernetTypePPPoEDiscovery
332 eth.EthernetType = layers.EthernetTypeDot1Q
333 priority = vpv.GetRemarkedPriority(priority)
334
335 var pktLayers []gopacket.SerializableLayer
336 pktLayers = append(pktLayers, eth)
337
338 var qVlans []of.VlanType
339 var qVlanLayers []gopacket.SerializableLayer
340
341 if vpv.AllowTransparent {
342 vlanThreshold := 2
343 // In case of ONU_CVLAN or OLT_SVLAN, the DS pkts have single configured vlan
344 // In case of ONU_CVLAN_OLT_SVLAN or OLT_CVLAN_OLT_SVLAN, the DS pkts have 2 configured vlan
345 // Based on that, the no. of vlans should be ignored to get only transparent vlans
346 if vpv.VlanControl == ONUCVlan || vpv.VlanControl == OLTSVlan || vpv.VlanControl == None {
347 vlanThreshold = 1
348 }
349 nxtLayer := layers.EthernetTypeDot1Q
350 if vlans := GetVlans(pkt); len(vlans) > vlanThreshold {
351 qVlans = vlans[vlanThreshold:]
352 cTagType = layers.EthernetTypeDot1Q
353 }
354 for i, qVlan := range qVlans {
355 vlan := uint16(qVlan)
356 if i == (len(qVlans) - 1) {
357 nxtLayer = layers.EthernetTypePPPoEDiscovery
358 }
359 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
360 qVlanLayers = append(qVlanLayers, qdot1q)
361 }
362 }
363
364 switch vpv.VlanControl {
365 case ONUCVlanOLTSVlan:
366 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.CVlan), DropEligible: dropEligible, Type: cTagType}
367 pktLayers = append(pktLayers, cdot1q)
368 case ONUCVlan,
369 None:
370 sdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.SVlan), DropEligible: dropEligible, Type: cTagType}
371 pktLayers = append(pktLayers, sdot1q)
372 case OLTCVlanOLTSVlan,
373 OLTSVlan:
374 udot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.UniVlan), DropEligible: dropEligible, Type: cTagType}
375 pktLayers = append(pktLayers, udot1q)
376 default:
377 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
378 return
379 }
380
381 pktLayers = append(pktLayers, qVlanLayers...)
382 pktLayers = append(pktLayers, pppoe)
383
384 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
385 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
386 logger.Errorw(ctx, "Packet Serialization Failed", log.Fields{"Reason": err.Error()})
387 return
388 }
389
390 if err := cntlr.GetController().PacketOutReq(device, vpv.Port, port, buff.Bytes(), false); err != nil {
391 logger.Warnw(ctx, "PacketOutReq Failed", log.Fields{"Device": device, "Error": err})
392 }
393}
394
395// ProcessUsPppoeIaPacket : The US PppoeIa packet is identified the PppoeIa OP in the packet. A request is considered upstream
396// and the service associated with the packet is located by the port and VLANs in the packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530397func (va *VoltApplication) ProcessUsPppoeIaPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530398 // We received the packet on an access port and the service for the packet can be
399 // gotten from the port and the packet
400 vpv, svc := va.GetVnetFromPkt(device, port, pkt)
401 if vpv == nil {
402 logger.Errorw(ctx, "VNET couldn't be found from packet", log.Fields{"Device": device, "Port": port})
403 return
404 }
405
406 outport, _ := va.GetNniPort(device)
407 if outport == "" || outport == "0" {
408 logger.Errorw(ctx, "NNI Port not found for device. Dropping Packet", log.Fields{"NNI": outport})
409 return
410 }
411
412 //Add PPPoE session for reference so that the DS pkts can be processed and re-directed
413 pppoeIaNws.AddPppoeIaSession(pkt, vpv)
414
415 // Extract the layers in the packet to prepare the outgoing packet
416 // We use the layers to build the outgoing packet from scratch as
417 // the packet received can't be modified to add/remove layers
418 eth := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
419 pppoe := pkt.Layer(layers.LayerTypePPPoE).(*layers.PPPoE)
420 msgType := pppoe.Code
421 logger.Infow(ctx, "Processing Southbound US PppoeIa packet", log.Fields{"Device": device, "Port": port, "Type": pppoe.Code})
422
423 AddIaOption(svc, pppoe)
424
425 // Learn the 8021P values from the packet received
426 var priority uint8
427 dropEligible := false
428 dot1ql := pkt.Layer(layers.LayerTypeDot1Q)
429 if dot1ql != nil {
430 dot1q := dot1ql.(*layers.Dot1Q)
431 priority = dot1q.Priority
432 dropEligible = dot1q.DropEligible
433 }
434
435 if vpv.PppoeIa {
436 //Maintain the session MAC as learnt MAC, since MAC is required for deletion of PPPoE session
437 if msgType == layers.PPPoECodePADI || msgType == layers.PPPoECodePADR {
438 if !util.MacAddrsMatch(vpv.MacAddr, eth.SrcMAC) {
439 expectedPort := va.GetMacInPortMap(eth.SrcMAC)
440 if expectedPort != "" && expectedPort != vpv.Port {
441 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-pppoe-message",
442 log.Fields{"MsgType": msgType, "ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": eth.SrcMAC.String()})
443 return
444 }
445 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530446 vpv.SetMacAddr(cntx, eth.SrcMAC)
Naveen Sampath04696f72022-06-13 15:19:14 +0530447 }
448
449 if pppoe.Code == layers.PPPoECodePADI {
450 vpv.SetPppoeIaState(PppoeIaStatePADI)
451 } else if pppoe.Code == layers.PPPoECodePADR {
452 vpv.SetPppoeIaState(PppoeIaStatePADR)
453 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530454 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530455 }
456
457 buff := gopacket.NewSerializeBuffer()
458 opts := gopacket.SerializeOptions{
459 FixLengths: true,
460 ComputeChecksums: true,
461 }
462
463 cTagType := layers.EthernetTypePPPoEDiscovery
464 outerVlan, innerVlan := vpv.GetNniVlans()
465 logger.Debugw(ctx, "Vnet Vlans", log.Fields{"Svlan": outerVlan, "Cvlan": innerVlan})
466 eth.EthernetType = vpv.SVlanTpid
467
468 var pktLayers []gopacket.SerializableLayer
469 pktLayers = append(pktLayers, eth)
470
471 var qVlans []of.VlanType
472 var qVlanLayers []gopacket.SerializableLayer
473
474 if vpv.AllowTransparent {
475 nxtLayer := layers.EthernetTypeDot1Q
476 if vlans := GetVlans(pkt); len(vlans) > 1 {
477 qVlans = vlans[1:]
478 logger.Debugw(ctx, "Q Vlans", log.Fields{"Vlan List": qVlans})
479 cTagType = layers.EthernetTypeDot1Q
480 }
481 for i, qVlan := range qVlans {
482 vlan := uint16(qVlan)
483 if i == (len(qVlans) - 1) {
484 nxtLayer = layers.EthernetTypePPPoEDiscovery
485 }
486 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
487 qVlanLayers = append(qVlanLayers, qdot1q)
488 }
489 }
490
491 switch vpv.VlanControl {
492 case ONUCVlanOLTSVlan,
493 OLTCVlanOLTSVlan:
494 sdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: layers.EthernetTypeDot1Q}
495 pktLayers = append(pktLayers, sdot1q)
496 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: innerVlan, DropEligible: dropEligible, Type: cTagType}
497 pktLayers = append(pktLayers, cdot1q)
498 case ONUCVlan,
499 OLTSVlan,
500 None:
501 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: cTagType}
502 pktLayers = append(pktLayers, cdot1q)
503 default:
504 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
505 return
506 }
507
508 pktLayers = append(pktLayers, qVlanLayers...)
509 pktLayers = append(pktLayers, pppoe)
510 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
511 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
512 return
513 }
514
515 // Now the packet constructed is output towards the switch to be emitted on
516 // the NNI port
517 if err := cntlr.GetController().PacketOutReq(device, outport, port, buff.Bytes(), false); err != nil {
518 logger.Warnw(ctx, "PacketOutReq Failed", log.Fields{"Device": device, "Error": err})
519 }
520
521}
522
523// ProcessPPPoEIaPacket to process Pppoeia packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530524func (va *VoltApplication) ProcessPPPoEIaPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530525 // Make some error checks before proceeding
526 pppoel := pkt.Layer(layers.LayerTypePPPoE)
527 if pppoel == nil {
528 return
529 }
530 _, ok := pppoel.(*layers.PPPoE)
531 if !ok {
532 return
533 }
534
535 // Let us assess the direction of the packet. We can do so by the port
536 // which is more reliable or do by the PPPoE code which is less reliable
537 isUs := true
538 if nni, _ := GetApplication().GetNniPort(device); nni == port {
539 isUs = false
540 }
541
542 // This is a valid PPPoE packet and can be processed
543 if isUs {
544 // This is treated as an upstream packet in the VOLT application
545 // as VOLT serves access subscribers who use DHCP to acquire IP
546 // address and these packets go upstream to the network
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530547 va.ProcessUsPppoeIaPacket(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530548 } else {
549 // This is a downstream packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530550 va.ProcessDsPppoeIaPacket(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530551 }
552}
553
554// ProcessPPPoEPacket to process Pppoe packet
555func (va *VoltApplication) ProcessPPPoEPacket(device string, port string, pkt gopacket.Packet) {
556 dpt := NewPppoeIaPacketTask(pkt, device, port)
557 va.pppoeTasks.AddTask(dpt)
558}
559
560// pppoeIaNws : The DHCP relay application is maintained within the structures below
561var pppoeIaNws *PppoeIaNetworks
562
563func init() {
564 pppoeIaNws = NewPppoeIaNetworks()
565 RegisterPacketHandler(PPPOE, ProcessPPPoEPacket)
566}
567
568// ProcessPPPoEPacket : CallBack function registered with application to handle PPPoE packetIn
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530569func ProcessPPPoEPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530570 GetApplication().ProcessPPPoEPacket(device, port, pkt)
571}
572
573// PppoeIaPacketTask : Task to add or delete flows of a service
574type PppoeIaPacketTask struct {
575 taskID uint8
576 ctx context.Context
577 pkt gopacket.Packet
578 device string
579 port string
580 timestamp string
581}
582
583// NewPppoeIaPacketTask constructor for PppoeIaPacketTask
584func NewPppoeIaPacketTask(pkt gopacket.Packet, dev string, port string) *PppoeIaPacketTask {
585 var dpt PppoeIaPacketTask
586 dpt.pkt = pkt
587 dpt.device = dev
588 dpt.port = port
589 dpt.timestamp = (time.Now()).Format(time.RFC3339Nano)
590 return &dpt
591}
592
593// Name to return name for PppoeIaPacketTask
594func (dpt *PppoeIaPacketTask) Name() string {
595 return "DHCP Packet Task"
596}
597
598// TaskID to return task id for PppoeIaPacketTask
599func (dpt *PppoeIaPacketTask) TaskID() uint8 {
600 return dpt.taskID
601}
602
603// Timestamp to return timestamp for PppoeIaPacketTask
604func (dpt *PppoeIaPacketTask) Timestamp() string {
605 return dpt.timestamp
606}
607
608// Stop to stop the PppoeIaPacketTask
609func (dpt *PppoeIaPacketTask) Stop() {
610}
611
612// Start to start PppoeIaPacketTask
613func (dpt *PppoeIaPacketTask) Start(ctx context.Context, taskID uint8) error {
614 dpt.taskID = taskID
615 dpt.ctx = ctx
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530616 GetApplication().ProcessPPPoEIaPacket(ctx, dpt.device, dpt.port, dpt.pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530617 return nil
618}