blob: 59207513c18285c1dbc747ac1712c0362a8f0ac2 [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 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530103 logger.Debugw(ctx, "NewPppoeIaRelayVnet", log.Fields{"OuterVlan": outerVlan, "innerVlan": innerVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530104 var drv PppoeIaRelayVnet
105
106 drv.OuterVlan = outerVlan
107 drv.InnerVlan = innerVlan
108 drv.sessions = util.NewConcurrentMap() //make(map[[6]byte]IPppoeIaSession)
109 return &drv
110}
111
112// AddPppoeIaRelayVnet add pppoeia relay vnet
113func (dn *PppoeIaNetworks) AddPppoeIaRelayVnet(outerVlan uint16, innerVlan uint16) *PppoeIaRelayVnet {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530114 logger.Debugw(ctx, "AddPppoeIaRelayVnet", log.Fields{"OuterVlan": outerVlan, "innerVlan": innerVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530115 comboVlan := uint32(outerVlan)<<16 + uint32(innerVlan)
116 if drv, ok := dn.Networks.Get(comboVlan); ok {
117 return drv.(*PppoeIaRelayVnet)
118 }
119 drv := NewPppoeIaRelayVnet(outerVlan, innerVlan)
120 dn.Networks.Set(comboVlan, drv)
121 return drv
122}
123
124// NewPppoeIaNetworks is constructor for PppoeIa network
125func NewPppoeIaNetworks() *PppoeIaNetworks {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530126 logger.Info(ctx, "NewPppoeIaNetworks")
Naveen Sampath04696f72022-06-13 15:19:14 +0530127 var dn PppoeIaNetworks
128 dn.Networks = util.NewConcurrentMap() //make(map[uint32]*PppoeIaRelayVnet)
129 return &dn
130}
131
132// AddPppoeIaSession to add pppoeia session
133func (dn *PppoeIaNetworks) AddPppoeIaSession(pkt gopacket.Packet, session IPppoeIaSession) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530134 logger.Info(ctx, "AddPppoeIaSession")
Naveen Sampath04696f72022-06-13 15:19:14 +0530135 var key [6]byte
136 ethl := pkt.Layer(layers.LayerTypeEthernet)
137 eth, _ := ethl.(*layers.Ethernet)
138 addr := eth.SrcMAC
139 copy(key[:], addr[0:6])
140 drv := dn.AddPppoeIaRelayVnet(session.GetNniVlans())
141 drv.sessions.Set(key, session)
142}
143
144// DelPppoeIaSession to delete pppoeia session
145func (dn *PppoeIaNetworks) DelPppoeIaSession(pkt gopacket.Packet, session IPppoeIaSession) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530146 logger.Info(ctx, "DelPppoeIaSession")
Naveen Sampath04696f72022-06-13 15:19:14 +0530147 var key [6]byte
148 ethl := pkt.Layer(layers.LayerTypeEthernet)
149 eth, _ := ethl.(*layers.Ethernet)
150 addr := eth.SrcMAC
151 if len(addr) != 6 {
152 logger.Errorw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
153 return
154 }
155 copy(key[:], addr[0:6])
156 drv := dn.AddPppoeIaRelayVnet(session.GetNniVlans())
157 drv.sessions.Remove(key)
158}
159
160// delPppoeIaSessions to delete pppoeia sessions
161func delPppoeIaSessions(addr net.HardwareAddr, outervlan of.VlanType, innervlan of.VlanType) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530162 logger.Infow(ctx, "delPppoeIaSessions", log.Fields{"Addr": addr, "OuterVlan": outervlan, "innerVlan": innervlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530163 var key [6]byte
164 if addr == nil || !NonZeroMacAddress(addr) {
165 logger.Warnw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
166 return
167 }
168 copy(key[:], addr[0:6])
169 drv := pppoeIaNws.AddPppoeIaRelayVnet(uint16(outervlan), uint16(innervlan))
170 drv.sessions.Remove(key)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530171 logger.Debugw(ctx, "PppoeIa Sessions deleted", log.Fields{"MAC": addr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530172}
173
174// GetPppoeIaSession to get pppoeia sessions
175func (dn *PppoeIaNetworks) GetPppoeIaSession(outerVlan uint16, innerVlan uint16, addr net.HardwareAddr) (IPppoeIaSession, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530176 logger.Debugw(ctx, "GetPppoeIaSession", log.Fields{"Addr": addr, "OuterVlan": outerVlan, "innerVlan": innerVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530177 var key [6]byte
178 if len(addr) != 6 {
179 logger.Errorw(ctx, "Invalid MAC address", log.Fields{"Addr": addr})
180 return nil, errors.New("Invalid MAC address")
181 }
182 copy(key[:], addr[0:6])
183 drv := dn.AddPppoeIaRelayVnet(outerVlan, innerVlan)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530184 logger.Debugw(ctx, "Key for PPPoE session", log.Fields{"Key": key})
Naveen Sampath04696f72022-06-13 15:19:14 +0530185 if session, ok := drv.sessions.Get(key); ok {
186 return session.(IPppoeIaSession), nil
187 }
188 return nil, ErrSessionDoNotExist
189}
190
191// GetVnetForNni to get vnet for nni port
192func GetVnetForNni(addr net.HardwareAddr, cvlan of.VlanType, svlan of.VlanType, pbit uint8) (*VoltPortVnet, error) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530193 var err error
194 var session IPppoeIaSession
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530195 logger.Infow(ctx, "GetVnetForNni, Mac Obtained MAC: ", log.Fields{"Addr": addr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530196 if session, err = pppoeIaNws.GetPppoeIaSession(uint16(svlan), uint16(cvlan), addr); err != nil {
197 logger.Errorw(ctx, "PPPoE Session retrieval failed", log.Fields{"Error": err})
198 if err == ErrSessionDoNotExist {
199 logger.Info(ctx, "Finding matching VPV from packet")
200 vpvs, err1 := GetApplication().GetVpvsForDsPkt(cvlan, svlan, addr, pbit)
201 if len(vpvs) == 1 {
202 return vpvs[0], nil
203 }
204 return nil, err1
205 }
206 return nil, err
207 }
208
209 if session != nil {
210 vpv, ok := session.(*VoltPortVnet)
211
212 if ok {
213 logger.Infow(ctx, "Session Exist: VPV found", log.Fields{"VPV": vpv})
214 return vpv, nil
215 }
216 }
217 logger.Error(ctx, "PPPoE Session retrieved of wrong type")
218 return nil, errors.New("The session retrieved of wrong type")
219}
220
221// AddIaOption : Addition of PppoeIa Option 82 which codes circuit-id and remote-id
222// into the packet. This happens as the request is relayed to the
223// PppoeIa servers on the NNI
224func AddIaOption(svc *VoltService, pppoe *layers.PPPoE) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530225 //NOTE : both cID and rID should not be empty if this function is called
226 var data []byte
227 cID := svc.GetCircuitID()
228 rID := svc.RemoteID
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530229 logger.Debugw(ctx, "AddIaOption", log.Fields{"cID": cID, "rID": rID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530230
231 if len(cID) != 0 || len(rID) != 0 || svc.isDataRateAttrPresent() {
232 data = append(data, DSLATTRVendorID...)
233 }
234
235 logger.Debugw(ctx, "Vendor Info", log.Fields{"Data": data})
236
237 if len(cID) != 0 {
238 data = append(data, TYPECIRCUITID)
239 data = append(data, byte(len(cID)))
240 data = append(data, cID...)
241 }
242 if len(rID) != 0 {
243 data = append(data, TYPEREMOTEID)
244 data = append(data, byte(len(rID)))
245 data = append(data, rID...)
246 }
247
248 if svc.isDataRateAttrPresent() {
249 minDrUs := util.Uint32ToByte(svc.MinDataRateUs)
250 data = append(data, TYPEMINDATAUS)
251 data = append(data, byte(len(minDrUs)))
252 data = append(data, minDrUs...)
253
254 minDrDs := util.Uint32ToByte(svc.MinDataRateDs)
255 data = append(data, TYPEMINDATADS)
256 data = append(data, byte(len(minDrDs)))
257 data = append(data, minDrDs...)
258
259 maxDrUs := util.Uint32ToByte(svc.MaxDataRateUs)
260 data = append(data, TYPEMAXDATAUS)
261 data = append(data, byte(len(maxDrUs)))
262 data = append(data, maxDrUs...)
263
264 maxDrDs := util.Uint32ToByte(svc.MaxDataRateDs)
265 data = append(data, TYPEMAXDATADS)
266 data = append(data, byte(len(maxDrDs)))
267 data = append(data, maxDrDs...)
268 }
269 option := layers.NewPPPoEOption(layers.PPPoEOptVendorSpecific, data)
270 pppoe.Options = append(pppoe.Options, option)
271}
272
273// DelIaOption for deletion of IA option from the packet received on the NNI interface.
274func DelIaOption(pppoe *layers.PPPoE) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530275 logger.Info(ctx, "DelIaOption")
Naveen Sampath04696f72022-06-13 15:19:14 +0530276 for index, option := range pppoe.Options {
277 if option.Type == layers.PPPoEOptVendorSpecific {
278 pppoe.Options = append(pppoe.Options[0:index], pppoe.Options[index+1:]...)
279 return
280 }
281 }
282}
283
284// ProcessDsPppoeIaPacket : This function processes DS PppoeIa packet received on the NNI port.
285// The services are attached to the access ports. Thus, the PppoeIa
286// session is derived from the list of PppoeIa sessions stored in the
287// common map. The key for retrieval includes the VLAN tags in the
288// the packet and the MAC address of the client.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530289func (va *VoltApplication) ProcessDsPppoeIaPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530290 // Retrieve the layers to build the outgoing packet. It is not
291 // possible to add/remove layers to the existing packet and thus
292 // the lyayers are extracted to build the outgoing packet
293 eth := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
294 pppoe := pkt.Layer(layers.LayerTypePPPoE).(*layers.PPPoE)
295
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530296 logger.Infow(ctx, "Processing Southbound DS PppoeIa packet", log.Fields{"Device": device, "Port": port, "Type": pppoe.Code})
Naveen Sampath04696f72022-06-13 15:19:14 +0530297
298 // Retrieve the priority and drop eligible flags from the
299 // packet received
300 var priority uint8
301 var dropEligible bool
302 dot1ql := pkt.Layer(layers.LayerTypeDot1Q)
303 if dot1ql != nil {
304 dot1q := dot1ql.(*layers.Dot1Q)
305 priority = dot1q.Priority
306 dropEligible = dot1q.DropEligible
307 }
308
309 pktInnerlan, pktOuterlan := GetVlansFromPacket(pkt)
310 vpv, err := GetVnetForNni(eth.DstMAC, pktInnerlan, pktOuterlan, priority)
311 if err != nil {
312 logger.Errorw(ctx, "VNET couldn't be found for NNI", log.Fields{"Error": err})
313 return
314 }
315
316 // Do not modify pppoe header if vnet's mac_learning type is not PPPoE-IA.
317 if vpv.PppoeIa {
318 // Delete the IA option that may be included in the response
319 DelIaOption(pppoe)
mgoudabb017dc2025-10-29 19:53:34 +0530320 switch pppoe.Code {
321 case layers.PPPoECodePADO:
Naveen Sampath04696f72022-06-13 15:19:14 +0530322 vpv.SetPppoeIaState(PppoeIaStatePADO)
mgoudabb017dc2025-10-29 19:53:34 +0530323 case layers.PPPoECodePADS:
Naveen Sampath04696f72022-06-13 15:19:14 +0530324 vpv.SetPppoeIaState(PppoeIaStatePADS)
mgoudabb017dc2025-10-29 19:53:34 +0530325 case layers.PPPoECodePADT:
Naveen Sampath04696f72022-06-13 15:19:14 +0530326 vpv.SetPppoeIaState(PppoeIaStatePADT)
327 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530328 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530329 }
330 // Create the outgoing bufer and set the checksum in the packet
331 buff := gopacket.NewSerializeBuffer()
332 opts := gopacket.SerializeOptions{
333 FixLengths: true,
334 ComputeChecksums: true,
335 }
336
337 cTagType := layers.EthernetTypePPPoEDiscovery
338 eth.EthernetType = layers.EthernetTypeDot1Q
339 priority = vpv.GetRemarkedPriority(priority)
340
341 var pktLayers []gopacket.SerializableLayer
342 pktLayers = append(pktLayers, eth)
343
344 var qVlans []of.VlanType
345 var qVlanLayers []gopacket.SerializableLayer
346
347 if vpv.AllowTransparent {
348 vlanThreshold := 2
349 // In case of ONU_CVLAN or OLT_SVLAN, the DS pkts have single configured vlan
350 // In case of ONU_CVLAN_OLT_SVLAN or OLT_CVLAN_OLT_SVLAN, the DS pkts have 2 configured vlan
351 // Based on that, the no. of vlans should be ignored to get only transparent vlans
352 if vpv.VlanControl == ONUCVlan || vpv.VlanControl == OLTSVlan || vpv.VlanControl == None {
353 vlanThreshold = 1
354 }
355 nxtLayer := layers.EthernetTypeDot1Q
356 if vlans := GetVlans(pkt); len(vlans) > vlanThreshold {
357 qVlans = vlans[vlanThreshold:]
358 cTagType = layers.EthernetTypeDot1Q
359 }
360 for i, qVlan := range qVlans {
361 vlan := uint16(qVlan)
362 if i == (len(qVlans) - 1) {
363 nxtLayer = layers.EthernetTypePPPoEDiscovery
364 }
365 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
366 qVlanLayers = append(qVlanLayers, qdot1q)
367 }
368 }
369
370 switch vpv.VlanControl {
371 case ONUCVlanOLTSVlan:
372 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.CVlan), DropEligible: dropEligible, Type: cTagType}
373 pktLayers = append(pktLayers, cdot1q)
374 case ONUCVlan,
375 None:
376 sdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.SVlan), DropEligible: dropEligible, Type: cTagType}
377 pktLayers = append(pktLayers, sdot1q)
378 case OLTCVlanOLTSVlan,
379 OLTSVlan:
380 udot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.UniVlan), DropEligible: dropEligible, Type: cTagType}
381 pktLayers = append(pktLayers, udot1q)
382 default:
383 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
384 return
385 }
386
387 pktLayers = append(pktLayers, qVlanLayers...)
388 pktLayers = append(pktLayers, pppoe)
389
390 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
391 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
392 logger.Errorw(ctx, "Packet Serialization Failed", log.Fields{"Reason": err.Error()})
393 return
394 }
395
396 if err := cntlr.GetController().PacketOutReq(device, vpv.Port, port, buff.Bytes(), false); err != nil {
397 logger.Warnw(ctx, "PacketOutReq Failed", log.Fields{"Device": device, "Error": err})
398 }
399}
400
401// ProcessUsPppoeIaPacket : The US PppoeIa packet is identified the PppoeIa OP in the packet. A request is considered upstream
402// and the service associated with the packet is located by the port and VLANs in the packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530403func (va *VoltApplication) ProcessUsPppoeIaPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530404 logger.Infow(ctx, "Processing Southbound US PppoeIa packet", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530405 // We received the packet on an access port and the service for the packet can be
406 // gotten from the port and the packet
407 vpv, svc := va.GetVnetFromPkt(device, port, pkt)
408 if vpv == nil {
409 logger.Errorw(ctx, "VNET couldn't be found from packet", log.Fields{"Device": device, "Port": port})
410 return
411 }
412
413 outport, _ := va.GetNniPort(device)
414 if outport == "" || outport == "0" {
415 logger.Errorw(ctx, "NNI Port not found for device. Dropping Packet", log.Fields{"NNI": outport})
416 return
417 }
418
419 //Add PPPoE session for reference so that the DS pkts can be processed and re-directed
420 pppoeIaNws.AddPppoeIaSession(pkt, vpv)
421
422 // Extract the layers in the packet to prepare the outgoing packet
423 // We use the layers to build the outgoing packet from scratch as
424 // the packet received can't be modified to add/remove layers
425 eth := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
426 pppoe := pkt.Layer(layers.LayerTypePPPoE).(*layers.PPPoE)
427 msgType := pppoe.Code
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530428 logger.Debugw(ctx, "Processing Southbound US PppoeIa packet", log.Fields{"Device": device, "Port": port, "Type": pppoe.Code})
Naveen Sampath04696f72022-06-13 15:19:14 +0530429
430 AddIaOption(svc, pppoe)
431
432 // Learn the 8021P values from the packet received
433 var priority uint8
434 dropEligible := false
435 dot1ql := pkt.Layer(layers.LayerTypeDot1Q)
436 if dot1ql != nil {
437 dot1q := dot1ql.(*layers.Dot1Q)
438 priority = dot1q.Priority
439 dropEligible = dot1q.DropEligible
440 }
441
442 if vpv.PppoeIa {
vinokuma926cb3e2023-03-29 11:41:06 +0530443 // Maintain the session MAC as learnt MAC, since MAC is required for deletion of PPPoE session
Naveen Sampath04696f72022-06-13 15:19:14 +0530444 if msgType == layers.PPPoECodePADI || msgType == layers.PPPoECodePADR {
445 if !util.MacAddrsMatch(vpv.MacAddr, eth.SrcMAC) {
446 expectedPort := va.GetMacInPortMap(eth.SrcMAC)
447 if expectedPort != "" && expectedPort != vpv.Port {
448 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-pppoe-message",
449 log.Fields{"MsgType": msgType, "ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": eth.SrcMAC.String()})
450 return
451 }
452 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530453 vpv.SetMacAddr(cntx, eth.SrcMAC)
Naveen Sampath04696f72022-06-13 15:19:14 +0530454 }
455
mgoudabb017dc2025-10-29 19:53:34 +0530456 switch pppoe.Code {
457 case layers.PPPoECodePADI:
Naveen Sampath04696f72022-06-13 15:19:14 +0530458 vpv.SetPppoeIaState(PppoeIaStatePADI)
mgoudabb017dc2025-10-29 19:53:34 +0530459 case layers.PPPoECodePADR:
Naveen Sampath04696f72022-06-13 15:19:14 +0530460 vpv.SetPppoeIaState(PppoeIaStatePADR)
461 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530462 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530463 }
464
465 buff := gopacket.NewSerializeBuffer()
466 opts := gopacket.SerializeOptions{
467 FixLengths: true,
468 ComputeChecksums: true,
469 }
470
471 cTagType := layers.EthernetTypePPPoEDiscovery
472 outerVlan, innerVlan := vpv.GetNniVlans()
473 logger.Debugw(ctx, "Vnet Vlans", log.Fields{"Svlan": outerVlan, "Cvlan": innerVlan})
474 eth.EthernetType = vpv.SVlanTpid
475
476 var pktLayers []gopacket.SerializableLayer
477 pktLayers = append(pktLayers, eth)
478
479 var qVlans []of.VlanType
480 var qVlanLayers []gopacket.SerializableLayer
481
482 if vpv.AllowTransparent {
483 nxtLayer := layers.EthernetTypeDot1Q
484 if vlans := GetVlans(pkt); len(vlans) > 1 {
485 qVlans = vlans[1:]
486 logger.Debugw(ctx, "Q Vlans", log.Fields{"Vlan List": qVlans})
487 cTagType = layers.EthernetTypeDot1Q
488 }
489 for i, qVlan := range qVlans {
490 vlan := uint16(qVlan)
491 if i == (len(qVlans) - 1) {
492 nxtLayer = layers.EthernetTypePPPoEDiscovery
493 }
494 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
495 qVlanLayers = append(qVlanLayers, qdot1q)
496 }
497 }
498
499 switch vpv.VlanControl {
500 case ONUCVlanOLTSVlan,
501 OLTCVlanOLTSVlan:
502 sdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: layers.EthernetTypeDot1Q}
503 pktLayers = append(pktLayers, sdot1q)
504 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: innerVlan, DropEligible: dropEligible, Type: cTagType}
505 pktLayers = append(pktLayers, cdot1q)
506 case ONUCVlan,
507 OLTSVlan,
508 None:
509 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: cTagType}
510 pktLayers = append(pktLayers, cdot1q)
511 default:
512 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
513 return
514 }
515
516 pktLayers = append(pktLayers, qVlanLayers...)
517 pktLayers = append(pktLayers, pppoe)
518 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
519 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
520 return
521 }
522
523 // Now the packet constructed is output towards the switch to be emitted on
524 // the NNI port
525 if err := cntlr.GetController().PacketOutReq(device, outport, port, buff.Bytes(), false); err != nil {
526 logger.Warnw(ctx, "PacketOutReq Failed", log.Fields{"Device": device, "Error": err})
527 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530528}
529
530// ProcessPPPoEIaPacket to process Pppoeia packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530531func (va *VoltApplication) ProcessPPPoEIaPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530532 logger.Infow(ctx, "Processing PPPoEIa packet", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530533 // Make some error checks before proceeding
534 pppoel := pkt.Layer(layers.LayerTypePPPoE)
535 if pppoel == nil {
536 return
537 }
538 _, ok := pppoel.(*layers.PPPoE)
539 if !ok {
540 return
541 }
542
543 // Let us assess the direction of the packet. We can do so by the port
544 // which is more reliable or do by the PPPoE code which is less reliable
545 isUs := true
546 if nni, _ := GetApplication().GetNniPort(device); nni == port {
547 isUs = false
548 }
549
550 // This is a valid PPPoE packet and can be processed
551 if isUs {
552 // This is treated as an upstream packet in the VOLT application
553 // as VOLT serves access subscribers who use DHCP to acquire IP
554 // address and these packets go upstream to the network
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530555 va.ProcessUsPppoeIaPacket(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530556 } else {
557 // This is a downstream packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530558 va.ProcessDsPppoeIaPacket(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530559 }
560}
561
562// ProcessPPPoEPacket to process Pppoe packet
563func (va *VoltApplication) ProcessPPPoEPacket(device string, port string, pkt gopacket.Packet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530564 logger.Debugw(ctx, "Processing PPPoE packet", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530565 dpt := NewPppoeIaPacketTask(pkt, device, port)
566 va.pppoeTasks.AddTask(dpt)
567}
568
569// pppoeIaNws : The DHCP relay application is maintained within the structures below
570var pppoeIaNws *PppoeIaNetworks
571
572func init() {
573 pppoeIaNws = NewPppoeIaNetworks()
574 RegisterPacketHandler(PPPOE, ProcessPPPoEPacket)
575}
576
577// ProcessPPPoEPacket : CallBack function registered with application to handle PPPoE packetIn
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530578func ProcessPPPoEPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530579 GetApplication().ProcessPPPoEPacket(device, port, pkt)
580}
581
582// PppoeIaPacketTask : Task to add or delete flows of a service
583type PppoeIaPacketTask struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530584 ctx context.Context
585 pkt gopacket.Packet
586 device string
587 port string
588 timestamp string
vinokuma926cb3e2023-03-29 11:41:06 +0530589 taskID uint8
Naveen Sampath04696f72022-06-13 15:19:14 +0530590}
591
592// NewPppoeIaPacketTask constructor for PppoeIaPacketTask
593func NewPppoeIaPacketTask(pkt gopacket.Packet, dev string, port string) *PppoeIaPacketTask {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530594 logger.Debugw(ctx, "New PPPoEIa packet", log.Fields{"Device": dev, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530595 var dpt PppoeIaPacketTask
596 dpt.pkt = pkt
597 dpt.device = dev
598 dpt.port = port
599 dpt.timestamp = (time.Now()).Format(time.RFC3339Nano)
600 return &dpt
601}
602
603// Name to return name for PppoeIaPacketTask
604func (dpt *PppoeIaPacketTask) Name() string {
605 return "DHCP Packet Task"
606}
607
608// TaskID to return task id for PppoeIaPacketTask
609func (dpt *PppoeIaPacketTask) TaskID() uint8 {
610 return dpt.taskID
611}
612
613// Timestamp to return timestamp for PppoeIaPacketTask
614func (dpt *PppoeIaPacketTask) Timestamp() string {
615 return dpt.timestamp
616}
617
618// Stop to stop the PppoeIaPacketTask
619func (dpt *PppoeIaPacketTask) Stop() {
620}
621
622// Start to start PppoeIaPacketTask
623func (dpt *PppoeIaPacketTask) Start(ctx context.Context, taskID uint8) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530624 logger.Debugw(ctx, "Start PPPoEIa task", log.Fields{"TaskID": taskID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530625 dpt.taskID = taskID
626 dpt.ctx = ctx
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530627 GetApplication().ProcessPPPoEIaPacket(ctx, dpt.device, dpt.port, dpt.pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530628 return nil
629}