blob: 6459d4c121b23d699fff4b36c4e553a8f4305056 [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)
320 if pppoe.Code == layers.PPPoECodePADO {
321 vpv.SetPppoeIaState(PppoeIaStatePADO)
322 } else if pppoe.Code == layers.PPPoECodePADS {
323 vpv.SetPppoeIaState(PppoeIaStatePADS)
324 } else if pppoe.Code == layers.PPPoECodePADT {
325 vpv.SetPppoeIaState(PppoeIaStatePADT)
326 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530327 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530328 }
329 // Create the outgoing bufer and set the checksum in the packet
330 buff := gopacket.NewSerializeBuffer()
331 opts := gopacket.SerializeOptions{
332 FixLengths: true,
333 ComputeChecksums: true,
334 }
335
336 cTagType := layers.EthernetTypePPPoEDiscovery
337 eth.EthernetType = layers.EthernetTypeDot1Q
338 priority = vpv.GetRemarkedPriority(priority)
339
340 var pktLayers []gopacket.SerializableLayer
341 pktLayers = append(pktLayers, eth)
342
343 var qVlans []of.VlanType
344 var qVlanLayers []gopacket.SerializableLayer
345
346 if vpv.AllowTransparent {
347 vlanThreshold := 2
348 // In case of ONU_CVLAN or OLT_SVLAN, the DS pkts have single configured vlan
349 // In case of ONU_CVLAN_OLT_SVLAN or OLT_CVLAN_OLT_SVLAN, the DS pkts have 2 configured vlan
350 // Based on that, the no. of vlans should be ignored to get only transparent vlans
351 if vpv.VlanControl == ONUCVlan || vpv.VlanControl == OLTSVlan || vpv.VlanControl == None {
352 vlanThreshold = 1
353 }
354 nxtLayer := layers.EthernetTypeDot1Q
355 if vlans := GetVlans(pkt); len(vlans) > vlanThreshold {
356 qVlans = vlans[vlanThreshold:]
357 cTagType = layers.EthernetTypeDot1Q
358 }
359 for i, qVlan := range qVlans {
360 vlan := uint16(qVlan)
361 if i == (len(qVlans) - 1) {
362 nxtLayer = layers.EthernetTypePPPoEDiscovery
363 }
364 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
365 qVlanLayers = append(qVlanLayers, qdot1q)
366 }
367 }
368
369 switch vpv.VlanControl {
370 case ONUCVlanOLTSVlan:
371 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.CVlan), DropEligible: dropEligible, Type: cTagType}
372 pktLayers = append(pktLayers, cdot1q)
373 case ONUCVlan,
374 None:
375 sdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.SVlan), DropEligible: dropEligible, Type: cTagType}
376 pktLayers = append(pktLayers, sdot1q)
377 case OLTCVlanOLTSVlan,
378 OLTSVlan:
379 udot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: uint16(vpv.UniVlan), DropEligible: dropEligible, Type: cTagType}
380 pktLayers = append(pktLayers, udot1q)
381 default:
382 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
383 return
384 }
385
386 pktLayers = append(pktLayers, qVlanLayers...)
387 pktLayers = append(pktLayers, pppoe)
388
389 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
390 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
391 logger.Errorw(ctx, "Packet Serialization Failed", log.Fields{"Reason": err.Error()})
392 return
393 }
394
395 if err := cntlr.GetController().PacketOutReq(device, vpv.Port, port, buff.Bytes(), false); err != nil {
396 logger.Warnw(ctx, "PacketOutReq Failed", log.Fields{"Device": device, "Error": err})
397 }
398}
399
400// ProcessUsPppoeIaPacket : The US PppoeIa packet is identified the PppoeIa OP in the packet. A request is considered upstream
401// and the service associated with the packet is located by the port and VLANs in the packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530402func (va *VoltApplication) ProcessUsPppoeIaPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530403 logger.Infow(ctx, "Processing Southbound US PppoeIa packet", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530404 // We received the packet on an access port and the service for the packet can be
405 // gotten from the port and the packet
406 vpv, svc := va.GetVnetFromPkt(device, port, pkt)
407 if vpv == nil {
408 logger.Errorw(ctx, "VNET couldn't be found from packet", log.Fields{"Device": device, "Port": port})
409 return
410 }
411
412 outport, _ := va.GetNniPort(device)
413 if outport == "" || outport == "0" {
414 logger.Errorw(ctx, "NNI Port not found for device. Dropping Packet", log.Fields{"NNI": outport})
415 return
416 }
417
418 //Add PPPoE session for reference so that the DS pkts can be processed and re-directed
419 pppoeIaNws.AddPppoeIaSession(pkt, vpv)
420
421 // Extract the layers in the packet to prepare the outgoing packet
422 // We use the layers to build the outgoing packet from scratch as
423 // the packet received can't be modified to add/remove layers
424 eth := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
425 pppoe := pkt.Layer(layers.LayerTypePPPoE).(*layers.PPPoE)
426 msgType := pppoe.Code
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530427 logger.Debugw(ctx, "Processing Southbound US PppoeIa packet", log.Fields{"Device": device, "Port": port, "Type": pppoe.Code})
Naveen Sampath04696f72022-06-13 15:19:14 +0530428
429 AddIaOption(svc, pppoe)
430
431 // Learn the 8021P values from the packet received
432 var priority uint8
433 dropEligible := false
434 dot1ql := pkt.Layer(layers.LayerTypeDot1Q)
435 if dot1ql != nil {
436 dot1q := dot1ql.(*layers.Dot1Q)
437 priority = dot1q.Priority
438 dropEligible = dot1q.DropEligible
439 }
440
441 if vpv.PppoeIa {
vinokuma926cb3e2023-03-29 11:41:06 +0530442 // Maintain the session MAC as learnt MAC, since MAC is required for deletion of PPPoE session
Naveen Sampath04696f72022-06-13 15:19:14 +0530443 if msgType == layers.PPPoECodePADI || msgType == layers.PPPoECodePADR {
444 if !util.MacAddrsMatch(vpv.MacAddr, eth.SrcMAC) {
445 expectedPort := va.GetMacInPortMap(eth.SrcMAC)
446 if expectedPort != "" && expectedPort != vpv.Port {
447 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-pppoe-message",
448 log.Fields{"MsgType": msgType, "ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": eth.SrcMAC.String()})
449 return
450 }
451 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530452 vpv.SetMacAddr(cntx, eth.SrcMAC)
Naveen Sampath04696f72022-06-13 15:19:14 +0530453 }
454
455 if pppoe.Code == layers.PPPoECodePADI {
456 vpv.SetPppoeIaState(PppoeIaStatePADI)
457 } else if pppoe.Code == layers.PPPoECodePADR {
458 vpv.SetPppoeIaState(PppoeIaStatePADR)
459 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530460 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530461 }
462
463 buff := gopacket.NewSerializeBuffer()
464 opts := gopacket.SerializeOptions{
465 FixLengths: true,
466 ComputeChecksums: true,
467 }
468
469 cTagType := layers.EthernetTypePPPoEDiscovery
470 outerVlan, innerVlan := vpv.GetNniVlans()
471 logger.Debugw(ctx, "Vnet Vlans", log.Fields{"Svlan": outerVlan, "Cvlan": innerVlan})
472 eth.EthernetType = vpv.SVlanTpid
473
474 var pktLayers []gopacket.SerializableLayer
475 pktLayers = append(pktLayers, eth)
476
477 var qVlans []of.VlanType
478 var qVlanLayers []gopacket.SerializableLayer
479
480 if vpv.AllowTransparent {
481 nxtLayer := layers.EthernetTypeDot1Q
482 if vlans := GetVlans(pkt); len(vlans) > 1 {
483 qVlans = vlans[1:]
484 logger.Debugw(ctx, "Q Vlans", log.Fields{"Vlan List": qVlans})
485 cTagType = layers.EthernetTypeDot1Q
486 }
487 for i, qVlan := range qVlans {
488 vlan := uint16(qVlan)
489 if i == (len(qVlans) - 1) {
490 nxtLayer = layers.EthernetTypePPPoEDiscovery
491 }
492 qdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: vlan, DropEligible: dropEligible, Type: nxtLayer}
493 qVlanLayers = append(qVlanLayers, qdot1q)
494 }
495 }
496
497 switch vpv.VlanControl {
498 case ONUCVlanOLTSVlan,
499 OLTCVlanOLTSVlan:
500 sdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: layers.EthernetTypeDot1Q}
501 pktLayers = append(pktLayers, sdot1q)
502 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: innerVlan, DropEligible: dropEligible, Type: cTagType}
503 pktLayers = append(pktLayers, cdot1q)
504 case ONUCVlan,
505 OLTSVlan,
506 None:
507 cdot1q := &layers.Dot1Q{Priority: priority, VLANIdentifier: outerVlan, DropEligible: dropEligible, Type: cTagType}
508 pktLayers = append(pktLayers, cdot1q)
509 default:
510 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
511 return
512 }
513
514 pktLayers = append(pktLayers, qVlanLayers...)
515 pktLayers = append(pktLayers, pppoe)
516 logger.Debugw(ctx, "Layers Count", log.Fields{"Count": len(pktLayers)})
517 if err := gopacket.SerializeMultiLayers(buff, opts, pktLayers); err != nil {
518 return
519 }
520
521 // Now the packet constructed is output towards the switch to be emitted on
522 // the NNI port
523 if err := cntlr.GetController().PacketOutReq(device, outport, port, buff.Bytes(), false); err != nil {
524 logger.Warnw(ctx, "PacketOutReq Failed", log.Fields{"Device": device, "Error": err})
525 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530526}
527
528// ProcessPPPoEIaPacket to process Pppoeia packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530529func (va *VoltApplication) ProcessPPPoEIaPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530530 logger.Infow(ctx, "Processing PPPoEIa packet", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530531 // Make some error checks before proceeding
532 pppoel := pkt.Layer(layers.LayerTypePPPoE)
533 if pppoel == nil {
534 return
535 }
536 _, ok := pppoel.(*layers.PPPoE)
537 if !ok {
538 return
539 }
540
541 // Let us assess the direction of the packet. We can do so by the port
542 // which is more reliable or do by the PPPoE code which is less reliable
543 isUs := true
544 if nni, _ := GetApplication().GetNniPort(device); nni == port {
545 isUs = false
546 }
547
548 // This is a valid PPPoE packet and can be processed
549 if isUs {
550 // This is treated as an upstream packet in the VOLT application
551 // as VOLT serves access subscribers who use DHCP to acquire IP
552 // address and these packets go upstream to the network
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530553 va.ProcessUsPppoeIaPacket(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530554 } else {
555 // This is a downstream packet
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530556 va.ProcessDsPppoeIaPacket(cntx, device, port, pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530557 }
558}
559
560// ProcessPPPoEPacket to process Pppoe packet
561func (va *VoltApplication) ProcessPPPoEPacket(device string, port string, pkt gopacket.Packet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530562 logger.Debugw(ctx, "Processing PPPoE packet", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530563 dpt := NewPppoeIaPacketTask(pkt, device, port)
564 va.pppoeTasks.AddTask(dpt)
565}
566
567// pppoeIaNws : The DHCP relay application is maintained within the structures below
568var pppoeIaNws *PppoeIaNetworks
569
570func init() {
571 pppoeIaNws = NewPppoeIaNetworks()
572 RegisterPacketHandler(PPPOE, ProcessPPPoEPacket)
573}
574
575// ProcessPPPoEPacket : CallBack function registered with application to handle PPPoE packetIn
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530576func ProcessPPPoEPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530577 GetApplication().ProcessPPPoEPacket(device, port, pkt)
578}
579
580// PppoeIaPacketTask : Task to add or delete flows of a service
581type PppoeIaPacketTask struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530582 ctx context.Context
583 pkt gopacket.Packet
584 device string
585 port string
586 timestamp string
vinokuma926cb3e2023-03-29 11:41:06 +0530587 taskID uint8
Naveen Sampath04696f72022-06-13 15:19:14 +0530588}
589
590// NewPppoeIaPacketTask constructor for PppoeIaPacketTask
591func NewPppoeIaPacketTask(pkt gopacket.Packet, dev string, port string) *PppoeIaPacketTask {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530592 logger.Debugw(ctx, "New PPPoEIa packet", log.Fields{"Device": dev, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530593 var dpt PppoeIaPacketTask
594 dpt.pkt = pkt
595 dpt.device = dev
596 dpt.port = port
597 dpt.timestamp = (time.Now()).Format(time.RFC3339Nano)
598 return &dpt
599}
600
601// Name to return name for PppoeIaPacketTask
602func (dpt *PppoeIaPacketTask) Name() string {
603 return "DHCP Packet Task"
604}
605
606// TaskID to return task id for PppoeIaPacketTask
607func (dpt *PppoeIaPacketTask) TaskID() uint8 {
608 return dpt.taskID
609}
610
611// Timestamp to return timestamp for PppoeIaPacketTask
612func (dpt *PppoeIaPacketTask) Timestamp() string {
613 return dpt.timestamp
614}
615
616// Stop to stop the PppoeIaPacketTask
617func (dpt *PppoeIaPacketTask) Stop() {
618}
619
620// Start to start PppoeIaPacketTask
621func (dpt *PppoeIaPacketTask) Start(ctx context.Context, taskID uint8) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530622 logger.Debugw(ctx, "Start PPPoEIa task", log.Fields{"TaskID": taskID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530623 dpt.taskID = taskID
624 dpt.ctx = ctx
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530625 GetApplication().ProcessPPPoEIaPacket(ctx, dpt.device, dpt.port, dpt.pkt)
Naveen Sampath04696f72022-06-13 15:19:14 +0530626 return nil
627}