[VOL-5458] - Multi NNI support in VGC
Change-Id: I4ed19bf43a5594109a16397da94c56cda87c69f0
Signed-off-by: Sridhar Ravindra <sridhar.ravindra@radisys.com>
diff --git a/VERSION b/VERSION
index c946ee6..1180819 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.6
+0.1.7
diff --git a/internal/pkg/application/application.go b/internal/pkg/application/application.go
index f0fa05e..4f390fd 100644
--- a/internal/pkg/application/application.go
+++ b/internal/pkg/application/application.go
@@ -160,6 +160,7 @@
Type VoltPortType
State PortState
ChannelPerSubAlarmRaised bool
+ NniDhcpTrapFlowAdded bool
}
// NewVoltPort : Constructor for the port.
@@ -209,26 +210,20 @@
MigratingServices *util.ConcurrentMap //<vnetID,<RequestID, MigrateServicesRequest>>
VpvsBySvlan *util.ConcurrentMap // map[svlan]map[vnet_port]*VoltPortVnet
ConfiguredVlanForDeviceFlows *util.ConcurrentMap //map[string]map[string]bool
-
- IgmpDsFlowAppliedForMvlan map[uint16]bool
-
- Ports sync.Map
- VlanPortStatus sync.Map
- ActiveChannelsPerPon sync.Map // [PonPortID]*PonPortCfg
- PonPortList sync.Map // [PonPortID]map[string]string
-
- State controller.DeviceState
- SouthBoundID string
- NniPort string
- Name string
- SerialNum string
-
- ActiveChannelCountLock sync.Mutex // This lock is used to update ActiveIGMPChannels
-
- NniDhcpTrapVid of.VlanType
-
- GlobalDhcpFlowAdded bool
- icmpv6GroupAdded bool
+ IgmpDsFlowAppliedForMvlan map[uint16]bool
+ Ports sync.Map
+ VlanPortStatus sync.Map
+ ActiveChannelsPerPon sync.Map // [PonPortID]*PonPortCfg
+ PonPortList sync.Map // [PonPortID]map[string]string
+ State controller.DeviceState
+ SouthBoundID string
+ Name string
+ SerialNum string
+ NniPort []string
+ ActiveChannelCountLock sync.Mutex // This lock is used to update ActiveIGMPChannels
+ NniDhcpTrapVid of.VlanType
+ GlobalDhcpFlowAdded bool
+ icmpv6GroupAdded bool
}
type VoltDevInterface interface {
@@ -241,7 +236,7 @@
d.Name = name
d.SouthBoundID = southBoundID
d.State = controller.DeviceStateDOWN
- d.NniPort = ""
+ d.NniPort = make([]string, 0)
d.SouthBoundID = southBoundID
d.SerialNum = slno
d.icmpv6GroupAdded = false
@@ -339,12 +334,21 @@
va.AggActiveChannelsCountPerSub(d.Name, port, p)
d.Ports.Store(port, p)
if util.IsNniPort(id) {
- d.NniPort = port
+ d.NniPort = append(d.NniPort, port)
}
addPonPortFromUniPort(p)
return p
}
+func (d *VoltDevice) IsPortNni(port string) bool {
+ for _, nniPort := range d.NniPort {
+ if nniPort == port {
+ return true
+ }
+ }
+ return false
+}
+
// GetPort to get port information from the device.
func (d *VoltDevice) GetPort(port string) *VoltPort {
logger.Debugw(ctx, "Get Port", log.Fields{"Port": port})
@@ -354,7 +358,7 @@
return nil
}
-// GetPortByPortID to get port information from the device.
+// GetPortNameFromPortID to get port information from the device.
func (d *VoltDevice) GetPortNameFromPortID(portID uint32) string {
logger.Debugw(ctx, "Get Port Name from the device", log.Fields{"PortID": portID})
portName := ""
@@ -368,6 +372,20 @@
return portName
}
+// GetPortIDFromPortName to get port information from the device.
+func (d *VoltDevice) GetPortIDFromPortName(portName string) uint32 {
+ logger.Debugw(ctx, "Get Port ID from the device", log.Fields{"PortName": portName})
+ var portID uint32
+ d.Ports.Range(func(key, value interface{}) bool {
+ vp := value.(*VoltPort)
+ if vp.Name == portName {
+ portID = vp.ID
+ }
+ return true
+ })
+ return portID
+}
+
// DelPort to delete port from the device
func (d *VoltDevice) DelPort(port string) {
logger.Debugw(ctx, "Delete Port from the device", log.Fields{"Port": port})
@@ -399,7 +417,7 @@
for _, vpv := range vnets.([]*VoltPortVnet) {
vpv.VpvLock.Lock()
- vpv.PortUpInd(cntx, d, port)
+ vpv.PortUpInd(cntx, d, port, "")
vpv.VpvLock.Unlock()
}
return true
@@ -419,7 +437,7 @@
type VoltAppInterface interface {
AddVnet(cntx context.Context, cfg VnetConfig, oper *VnetOper) error
AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error
- AddDeviceConfig(cntx context.Context, serialNum, hardwareIdentifier, nasID, ipAddress, uplinkPort string, nniDhcpTrapID uint16) error
+ AddDeviceConfig(cntx context.Context, serialNum, hardwareIdentifier, nasID, ipAddress, uplinkPort string, nniDhcpTrapID uint16, nniPorts []string) error
GetFlowProvisionStatus(portNo string) FlowProvisionStatus
DelServiceWithPrefix(cntx context.Context, prefix string) error
GetDevice(device string) *VoltDevice
@@ -499,12 +517,13 @@
}
type DeviceConfig struct {
- SerialNumber string `json:"id"`
- HardwareIdentifier string `json:"hardwareIdentifier"`
- IPAddress string `json:"ipAddress"`
- UplinkPort string `json:"uplinkPort"`
- NasID string `json:"nasId"`
- NniDhcpTrapVid uint16 `json:"nniDhcpTrapVid"`
+ SerialNumber string `json:"id"`
+ HardwareIdentifier string `json:"hardwareIdentifier"`
+ IPAddress string `json:"ipAddress"`
+ UplinkPort string `json:"uplinkPort"`
+ NasID string `json:"nasId"`
+ NniPorts []string `json:"nniPorts"`
+ NniDhcpTrapVid uint16 `json:"nniDhcpTrapVid"`
}
// PonPortCfg contains NB port config and activeIGMPChannels count
@@ -602,7 +621,7 @@
continue
}
logger.Debugw(ctx, "Retrieved device config", log.Fields{"Device Config": devConfig})
- if err := va.AddDeviceConfig(cntx, devConfig.SerialNumber, devConfig.HardwareIdentifier, devConfig.NasID, devConfig.IPAddress, devConfig.UplinkPort, devConfig.NniDhcpTrapVid); err != nil {
+ if err := va.AddDeviceConfig(cntx, devConfig.SerialNumber, devConfig.HardwareIdentifier, devConfig.NasID, devConfig.IPAddress, devConfig.UplinkPort, devConfig.NniDhcpTrapVid, devConfig.NniPorts); err != nil {
logger.Warnw(ctx, "Add device config failed", log.Fields{"DeviceConfig": devConfig, "Error": err})
}
}
@@ -621,7 +640,7 @@
return nil
}
-func (va *VoltApplication) AddDeviceConfig(cntx context.Context, serialNum, hardwareIdentifier, nasID, ipAddress, uplinkPort string, nniDhcpTrapID uint16) error {
+func (va *VoltApplication) AddDeviceConfig(cntx context.Context, serialNum, hardwareIdentifier, nasID, ipAddress, uplinkPort string, nniDhcpTrapID uint16, nniPorts []string) error {
logger.Debugw(ctx, "Received Add device config", log.Fields{"SerialNumber": serialNum, "HardwareIdentifier": hardwareIdentifier, "NasID": nasID, "IPAddress": ipAddress, "UplinkPort": uplinkPort, "NniDhcpTrapID": nniDhcpTrapID})
var dc *DeviceConfig
@@ -632,6 +651,7 @@
UplinkPort: uplinkPort,
IPAddress: ipAddress,
NniDhcpTrapVid: nniDhcpTrapID,
+ NniPorts: nniPorts,
}
va.DevicesConfig.Store(serialNum, deviceConfig)
err := dc.WriteDeviceConfigToDb(cntx, serialNum, deviceConfig)
@@ -1139,13 +1159,29 @@
// port which is a result of protection methods applied.
func (va *VoltApplication) GetNniPort(device string) (string, error) {
logger.Debugw(ctx, "NNI Get Ind", log.Fields{"device": device})
- va.portLock.Lock()
- defer va.portLock.Unlock()
d, ok := va.DevicesDisc.Load(device)
if !ok {
return "", errors.New("device doesn't exist")
}
- return d.(*VoltDevice).NniPort, nil
+ devConfig := va.GetDeviceConfig(d.(*VoltDevice).SerialNum)
+ if devConfig == nil {
+ return "", fmt.Errorf("device config not found for serial number %s", d.(*VoltDevice).SerialNum)
+ }
+ if len(d.(*VoltDevice).NniPort) > 0 {
+ for _, nniPort := range d.(*VoltDevice).NniPort {
+ nniPortID, err := GetApplication().GetPortID(nniPort)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting port ID by port Name", log.Fields{"Error": err})
+ continue
+ }
+ if devConfig.UplinkPort == strconv.Itoa(int(nniPortID)) {
+ logger.Debugw(ctx, "NNI port configured from NB", log.Fields{"NB NNI Port": devConfig.UplinkPort, "SB NNI Ports": d.(*VoltDevice).NniPort})
+ return nniPort, nil // Match found
+ }
+ }
+ }
+ // If no matching NNI port is found, return an error
+ return "", errors.New("nni port doesn't exist")
}
// NniDownInd process for Nni down indication.
@@ -1215,7 +1251,11 @@
func (va *VoltApplication) ProcessIgmpDSFlowForMvlan(cntx context.Context, d *VoltDevice, mvp *MvlanProfile, addFlow bool) {
logger.Debugw(ctx, "Process IGMP DS Flows for MVlan", log.Fields{"device": d.Name, "Mvlan": mvp.Mvlan, "addFlow": addFlow})
portState := false
- p := d.GetPort(d.NniPort)
+ nniPort, err := va.GetNniPort(d.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error gettin NNI port", log.Fields{"Error": err})
+ }
+ p := d.GetPort(nniPort)
if p != nil && p.State == PortStateUp {
portState = true
}
@@ -1438,9 +1478,12 @@
if p.Type == VoltPortTypeNni {
logger.Debugw(ctx, "Received NNI Port Ind: UP", log.Fields{"Device": device, "PortName": port, "PortId": p.ID})
- //va.PushDevFlowForDevice(d)
- //Build Igmp TrapFlowRule
- //va.ProcessIgmpDSFlowForDevice(d, true)
+ if d.NniDhcpTrapVid == 1 {
+ err := va.AddDefaultDhcpTrapFlow(cntx, d, p)
+ if err != nil {
+ logger.Errorw(ctx, "Failed adding DHCP trap flow", log.Fields{"Device": device, "PortName": port, "PortId": p.ID, "error": err})
+ }
+ }
}
vpvs, ok := va.VnetsByPort.Load(port)
if !ok || nil == vpvs || len(vpvs.([]*VoltPortVnet)) == 0 {
@@ -1450,7 +1493,7 @@
}
// If NNI port is not UP, do not push Flows
- if d.NniPort == "" {
+ if len(d.NniPort) == 0 {
logger.Warnw(ctx, "NNI port not UP. Not sending Port UP Ind for VPVs", log.Fields{"NNI": d.NniPort})
return
}
@@ -1458,12 +1501,12 @@
for _, vpv := range vpvs.([]*VoltPortVnet) {
vpv.VpvLock.Lock()
// If no service is activated drop the portUpInd
- if vpv.IsServiceActivated(cntx) {
+ if ok, nniPort := vpv.IsServiceActivated(cntx); ok {
// Do not trigger indication for the vpv which is already removed from vpv list as
// part of service delete (during the lock wait duration)
// In that case, the services associated wil be zero
if vpv.servicesCount.Load() != 0 {
- vpv.PortUpInd(cntx, d, port)
+ vpv.PortUpInd(cntx, d, port, nniPort)
}
} else {
// Service not activated, still attach device to service
@@ -1801,7 +1844,7 @@
if flow.FlowCount >= uint32(controller.GetController().GetMaxFlowRetryAttempt()) {
devConfig := va.GetDeviceConfig(devSerialNum)
if devConfig != nil {
- portNo := util.GetUniPortFromFlow(devConfig.UplinkPort, flow)
+ portNo := util.GetUniPortFromFlow(devConfig.UplinkPort, devConfig.NniPorts, flow)
portName, err := va.GetPortName(portNo)
if err != nil {
logger.Warnw(ctx, "Error getting port name", log.Fields{"Reason": err.Error(), "PortID": portNo})
diff --git a/internal/pkg/application/application_test.go b/internal/pkg/application/application_test.go
index 3372266..5eef192 100644
--- a/internal/pkg/application/application_test.go
+++ b/internal/pkg/application/application_test.go
@@ -740,7 +740,7 @@
SerialNum: "SDX6320033",
SouthBoundID: "68580342-6b3e-57cb-9ea4-06125594e330",
State: controller.DeviceStateDOWN,
- NniPort: "",
+ NniPort: make([]string, 0),
icmpv6GroupAdded: false,
IgmpDsFlowAppliedForMvlan: make(map[uint16]bool),
ConfiguredVlanForDeviceFlows: util.NewConcurrentMap(),
@@ -1308,6 +1308,7 @@
ipAddress string
uplinkPort string
nniDhcpTrapID uint16
+ nniPorts []string
}
dvcConfg := &DeviceConfig{
SerialNumber: "SDX6320031",
@@ -1351,7 +1352,7 @@
dbintf := mocks.NewMockDBIntf(gomock.NewController(t))
db = dbintf
dbintf.EXPECT().PutDeviceConfig(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
- if err := va.AddDeviceConfig(tt.args.cntx, tt.args.serialNum, tt.args.hardwareIdentifier, tt.args.nasID, tt.args.ipAddress, tt.args.uplinkPort, tt.args.nniDhcpTrapID); (err != nil) != tt.wantErr {
+ if err := va.AddDeviceConfig(tt.args.cntx, tt.args.serialNum, tt.args.hardwareIdentifier, tt.args.nasID, tt.args.ipAddress, tt.args.uplinkPort, tt.args.nniDhcpTrapID, tt.args.nniPorts); (err != nil) != tt.wantErr {
t.Errorf("VoltApplication.AddDeviceConfig() error = %v, wantErr %v", err, tt.wantErr)
}
})
@@ -1758,7 +1759,7 @@
Name: "49686e2d-618f-4e8e-bca0-442ab850a63a",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777216",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a123",
}
nbd := &NbDevice{
@@ -1827,7 +1828,7 @@
Name: "49686e2d-618f-4e8e-bca0-442ab850a63a",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777216",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a123",
}
tests := []struct {
@@ -1883,7 +1884,7 @@
Name: "49686e2d-618f-4e8e-bca0-442ab850a63a",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777216",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a123",
}
tests := []struct {
@@ -1935,7 +1936,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777216",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a123",
}
tests := []struct {
@@ -2000,7 +2001,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777216",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a",
}
nbd := &NbDevice{
@@ -2076,7 +2077,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777216",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a",
ActiveChannelsPerPon: sync.Map{},
}
@@ -2181,7 +2182,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777216",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a",
ActiveChannelsPerPon: sync.Map{},
}
@@ -2258,7 +2259,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777216",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a",
}
tests := []struct {
@@ -2302,7 +2303,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777216",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a",
}
tests := []struct {
@@ -2399,7 +2400,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777216",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a",
Ports: sync.Map{},
}
@@ -2546,7 +2547,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777472",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a",
Ports: sync.Map{},
VpvsBySvlan: util.NewConcurrentMap(),
@@ -2606,6 +2607,7 @@
voltPortVnet.services.Store("SDX6320031-1_SDX6320031-1-4096-2310-4096-65", voltServ)
voltapp := GetApplication()
voltapp.DevicesDisc.Store("SDX6320031", voltDev)
+ voltapp.DevicesConfig.Store("SDX6320031", &DeviceConfig{UplinkPort: "16777216"})
dbintf := mocks.NewMockDBIntf(gomock.NewController(t))
db = dbintf
dbintf.EXPECT().PutVpv(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
@@ -2624,7 +2626,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777472",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a",
Ports: sync.Map{},
VpvsBySvlan: util.NewConcurrentMap(),
@@ -3137,7 +3139,7 @@
Name: "49686e2d-618f-4e8e-bca0",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
- NniPort: "16777472",
+ NniPort: []string{"16777216"},
SouthBoundID: "49686e2d-618f-4e8e-bca0-442ab850a63a",
Ports: sync.Map{},
VpvsBySvlan: util.NewConcurrentMap(),
@@ -3604,7 +3606,7 @@
SerialNum: "SDX6320031",
IgmpDsFlowAppliedForMvlan: mblan,
Ports: sync.Map{},
- NniPort: "16777472",
+ NniPort: []string{"16777216"},
}
devicesList := make(map[string]OperInProgress)
devicesList["SDX6320030"] = opt82
diff --git a/internal/pkg/application/dhcprelay_test.go b/internal/pkg/application/dhcprelay_test.go
index 66edc57..d27ee8e 100644
--- a/internal/pkg/application/dhcprelay_test.go
+++ b/internal/pkg/application/dhcprelay_test.go
@@ -37,7 +37,7 @@
Name: "11c3175b-50f3-4220-9555-93df733ded1d",
SerialNum: "SDX6320031",
SouthBoundID: "68580342-6b3e-57cb-9ea4-06125594e330",
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
Ports: sync.Map{},
PonPortList: sync.Map{},
}
@@ -1115,7 +1115,7 @@
Name: "11c3175b-50f3-4220-9555-93df733ded1d",
SerialNum: "SDX6320031",
SouthBoundID: "68580342-6b3e-57cb-9ea4-06125594e330",
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
Ports: sync.Map{},
PonPortList: sync.Map{},
}
diff --git a/internal/pkg/application/igmpprofiles.go b/internal/pkg/application/igmpprofiles.go
index 2683a06..f26e33b 100644
--- a/internal/pkg/application/igmpprofiles.go
+++ b/internal/pkg/application/igmpprofiles.go
@@ -318,7 +318,11 @@
if err := mvp.WriteToDb(cntx); err != nil {
logger.Errorw(ctx, "Mvlan profile write to DB failed", log.Fields{"ProfileName": mvp.Name})
}
- return cntlr.GetController().DelFlows(cntx, device.NniPort, device.Name, flow, false)
+ nniPort, err := GetApplication().GetNniPort(device.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
+ }
+ return cntlr.GetController().DelFlows(cntx, nniPort, device.Name, flow, false)
}
// FlowRemoveSuccess - Process flow success indication
@@ -404,8 +408,11 @@
logger.Warnw(ctx, "Skipping Igmp & Mcast Flow processing: Device Not Found", log.Fields{"Device_SrNo": OLTSerialNum, "Mvlan": mvp.Mvlan})
return
}
-
- p := d.GetPort(d.NniPort)
+ nniPort, err := GetApplication().GetNniPort(d.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
+ }
+ p := d.GetPort(nniPort)
if p != nil && p.State == PortStateUp {
logger.Infow(ctx, "NNI Port Status is: UP & Vlan Enabled", log.Fields{"Device": d, "port": p})
@@ -432,7 +439,11 @@
defer mvp.mvpLock.RUnlock()
if d, _ := GetApplication().GetDeviceBySerialNo(oltSerialNum); d != nil {
- p := d.GetPort(d.NniPort)
+ nniPort, err := GetApplication().GetNniPort(d.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
+ }
+ p := d.GetPort(nniPort)
if p != nil {
logger.Infow(ctx, "NNI Port Status is: UP", log.Fields{"Device": d, "port": p})
@@ -482,7 +493,11 @@
if !ok || !flowAlreadyApplied {
flows, err := mvp.BuildIgmpDSFlows(device)
if err == nil {
- err = cntlr.GetController().AddFlows(cntx, d.NniPort, device, flows)
+ nniPort, err1 := va.GetNniPort(device)
+ if err1 != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err1})
+ }
+ err = cntlr.GetController().AddFlows(cntx, nniPort, device, flows)
if err != nil {
logger.Warnw(ctx, "Configuring IGMP Flow for device failed ", log.Fields{"Device": device, "err": err})
return err
@@ -1024,7 +1039,7 @@
vp.ChannelPerSubAlarmRaised = false
} else if mvp.MaxActiveChannels < vp.ActiveChannels && !vp.ChannelPerSubAlarmRaised {
/* When the max active channel count is reduced via update, we raise an alarm.
- But the previous excess channels still exist until a leave or expiry */
+ But the previous excess channels still exist until a leave or expiry */
serviceName := GetMcastServiceForSubAlarm(vp, mvp)
logger.Debugw(ctx, "Raising-SendActiveChannelPerSubscriberAlarm-due-to-update", log.Fields{"ActiveChannels": vp.ActiveChannels, "ServiceName": serviceName})
vp.ChannelPerSubAlarmRaised = true
diff --git a/internal/pkg/application/igmpprofiles_test.go b/internal/pkg/application/igmpprofiles_test.go
index e3b7328..411426f 100644
--- a/internal/pkg/application/igmpprofiles_test.go
+++ b/internal/pkg/application/igmpprofiles_test.go
@@ -473,7 +473,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
Ports: sync.Map{},
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
}
voltPort := &VoltPort{
Name: "16777472",
@@ -527,7 +527,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
Ports: sync.Map{},
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
FlowDelEventMap: util.NewConcurrentMap(),
}
va.DevicesDisc.Store("SDX6320031", d)
@@ -580,7 +580,7 @@
Name: "SDX6320031",
SerialNum: "SDX6320031",
Ports: sync.Map{},
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
FlowDelEventMap: util.NewConcurrentMap(),
}
va.DevicesDisc.Store("SDX6320031", d)
diff --git a/internal/pkg/application/pppoeia_test.go b/internal/pkg/application/pppoeia_test.go
index 0b8ed04..5c9aeac 100644
--- a/internal/pkg/application/pppoeia_test.go
+++ b/internal/pkg/application/pppoeia_test.go
@@ -199,7 +199,7 @@
va.DevicesDisc.Store(test_device, voltDevice)
pkt.EXPECT().Layers().Return(LayerTypeDot2Q).Times(3)
voltPortVnet1[0].SVlan = 0
- voltDevice.NniPort = "1"
+ voltDevice.NniPort = []string{"1"}
va.VnetsByPort.Store("test_port", voltPortVnet1)
voltPortVnet1[0].PppoeIa = true
voltPortVnet1[0].AllowTransparent = true
diff --git a/internal/pkg/application/service.go b/internal/pkg/application/service.go
index ae6f313..9a771f9 100644
--- a/internal/pkg/application/service.go
+++ b/internal/pkg/application/service.go
@@ -87,6 +87,7 @@
Name string
CircuitID string
Port string
+ NniPort string
UsMeterProfile string
DsMeterProfile string
AggDsMeterProfile string
@@ -574,12 +575,27 @@
flow := &of.VoltFlow{}
flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
- // Get the out and in ports for the flows
device, err := GetApplication().GetDeviceFromPort(vs.Port)
if err != nil {
- return nil, fmt.Errorf("Error Getting Device for Service %s and Port %s : %w", vs.Name, vs.Port, err)
+ return nil, fmt.Errorf("error getting device for service %s and port %s : %w", vs.Name, vs.Port, err)
}
- inport, _ := GetApplication().GetPortID(device.NniPort)
+ // inport will be obtained from nniPort of service else we'll use the default nni port
+ var inport uint32
+ // Get the out and in ports for the flows
+ if vs.NniPort != "" {
+ if nniPortID := device.GetPortIDFromPortName(vs.NniPort); nniPortID != 0 {
+ inport = nniPortID
+ } else {
+ return nil, fmt.Errorf("error getting portID for NNI port %s of Service %s", vs.NniPort, vs.Name)
+ }
+ } else {
+ nniPort, err1 := GetApplication().GetNniPort(device.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err1})
+ return nil, err1
+ }
+ inport, _ = GetApplication().GetPortID(nniPort)
+ }
outport, _ := GetApplication().GetPortID(vs.Port)
// PortName and PortID to be used for validation of port before flow pushing
flow.PortID = outport
@@ -757,12 +773,27 @@
flow := &of.VoltFlow{}
flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
- // Get the out and in ports for the flows
device, err := GetApplication().GetDeviceFromPort(vs.Port)
if err != nil {
- return nil, errorCodes.ErrDeviceNotFound
+ return nil, fmt.Errorf("error getting device for service %s and port %s : %w", vs.Name, vs.Port, err)
}
- outport, _ := GetApplication().GetPortID(device.NniPort)
+ // outport will be obtained from nniPort of service else we'll use the default nni port
+ var outport uint32
+ // Get the out and in ports for the flows
+ if vs.NniPort != "" {
+ if nniPortID := device.GetPortIDFromPortName(vs.NniPort); nniPortID != 0 {
+ outport = nniPortID
+ } else {
+ return nil, fmt.Errorf("error getting portID for NNI port %s of Service %s : %w", vs.NniPort, vs.Name, err)
+ }
+ } else {
+ nniPort, err := GetApplication().GetNniPort(device.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
+ return nil, err
+ }
+ outport, _ = GetApplication().GetPortID(nniPort)
+ }
inport, _ := GetApplication().GetPortID(vs.Port)
// PortName and PortID to be used for validation of port before flow pushing
flow.PortID = inport
@@ -2192,7 +2223,11 @@
if p.State == PortStateUp {
if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
// PortUp call initiates flow addition
- vpv.PortUpInd(cntx, device, portNo)
+ // The flow generation and pushing the flow can be done in a go routine,
+ // VGC once service is activated remembers and pushes the flows again
+ // if there was a restart in VGC during the execution of the go routine.
+ // Making it as a go routine will not impact anything
+ go vpv.PortUpInd(cntx, device, portNo, vs.NniPort)
} else {
logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
}
diff --git a/internal/pkg/application/service_test.go b/internal/pkg/application/service_test.go
index 746666a..76b0ec9 100644
--- a/internal/pkg/application/service_test.go
+++ b/internal/pkg/application/service_test.go
@@ -48,7 +48,7 @@
FlowDelEventMap: util.NewConcurrentMap(),
SerialNum: "test_serial_number",
ConfiguredVlanForDeviceFlows: util.NewConcurrentMap(),
- NniPort: "16777216",
+ NniPort: []string{"16777216"},
}
var voltMeter = &VoltMeter{
@@ -327,6 +327,7 @@
dbintf.EXPECT().PutService(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
ga.PortsDisc.Store(test_device, voltPort)
ga.DevicesDisc.Store(test_device, voltDevice)
+ ga.DevicesConfig.Store("test_serial_number", &DeviceConfig{UplinkPort: "16777216"})
vs.SvcUpInd(tt.args.cntx)
})
}
diff --git a/internal/pkg/application/vnets.go b/internal/pkg/application/vnets.go
index 80e8212..ef60ce3 100644
--- a/internal/pkg/application/vnets.go
+++ b/internal/pkg/application/vnets.go
@@ -749,7 +749,7 @@
// vpv.DsFlowsApplied = false
// vpv.UsFlowsApplied = false
vpv.VpvLock.Lock()
- vpv.PortUpInd(cntx, d, vpv.Port)
+ vpv.PortUpInd(cntx, d, vpv.Port, "")
vpv.VpvLock.Unlock()
}
@@ -758,7 +758,7 @@
// again here to apply the latest configuration if the configuration
// changed. Thus, a reboot of ONT forces the new configuration to get
// applied.
-func (vpv *VoltPortVnet) PortUpInd(cntx context.Context, device *VoltDevice, port string) {
+func (vpv *VoltPortVnet) PortUpInd(cntx context.Context, device *VoltDevice, port string, nniPort string) {
logger.Infow(ctx, "Port UP Ind, pushing flows for the port", log.Fields{"Device": device, "Port": port, "VnetDhcp": vpv.DhcpRelay, "McastService": vpv.McastService})
if vpv.DeleteInProgress {
logger.Warnw(ctx, "Ignoring VPV Port UP Ind, VPV deletion In-Progress", log.Fields{"Device": device, "Port": port, "Vnet": vpv.VnetName})
@@ -766,20 +766,17 @@
}
vpv.setDevice(device.Name)
- nni, _ := GetApplication().GetNniPort(device.Name)
- if nni == "" {
- logger.Warnw(ctx, "Ignoring Vnet Port UP indication: NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": device.Name})
- return
- }
-
- if nniPort := device.GetPort(nni); nniPort != nil {
- //If NNI port is not mached to nb nni port dont send flows
- devConfig := GetApplication().GetDeviceConfig(device.SerialNum)
- if devConfig != nil {
- if devConfig.UplinkPort != strconv.Itoa(int(nniPort.ID)) {
- logger.Warnw(ctx, "NNI port not configured from NB, not pushing flows", log.Fields{"NB NNI Port": devConfig.UplinkPort, "SB NNI port": nniPort.ID})
- return
- }
+ if nniPort != "" {
+ err := vpv.ValidateNniPort(device, nniPort)
+ if err != nil {
+ logger.Warnw(ctx, "Ignoring Vnet Port UP indication: NNI is not configured", log.Fields{"Port": vpv.Port, "Device": device.Name, "NNI": nniPort, "Error": err})
+ return
+ }
+ } else {
+ nni, err := GetApplication().GetNniPort(device.Name)
+ if nni == "" {
+ logger.Warnw(ctx, "Ignoring Vnet Port UP indication: Default NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": device.Name, "Error": err})
+ return
}
}
@@ -1012,6 +1009,40 @@
return dsPbit
}
+func (vpv *VoltPortVnet) ValidateNniPort(device *VoltDevice, nniPortName string) error {
+ devConfig := GetApplication().GetDeviceConfig(device.SerialNum)
+ if devConfig == nil {
+ return fmt.Errorf("device config not found for serial number %s", device.SerialNum)
+ }
+
+ var nniPort string
+ var nniPortID uint32
+ if nniPortID = device.GetPortIDFromPortName(nniPortName); nniPortID == 0 {
+ logger.Errorw(ctx, "Port Not Found", log.Fields{"NNI Port": nniPortName})
+ return errors.New("port not found for service")
+ }
+ if !device.IsPortNni(nniPortName) {
+ logger.Errorw(ctx, "Port Not Found in device", log.Fields{"NNI Port": nniPortName})
+ return fmt.Errorf("port not found in device")
+ }
+
+ nniPort = strconv.Itoa(int(nniPortID))
+ if len(devConfig.NniPorts) > 0 {
+ for _, port := range devConfig.NniPorts {
+ if port == nniPort {
+ logger.Debugw(ctx, "NNI port is configured from NB", log.Fields{"NB NniPorts": devConfig.NniPorts, "NniPort": nniPortName})
+ return nil // Match found
+ }
+ }
+ } else {
+ if devConfig.UplinkPort == nniPort {
+ logger.Debugw(ctx, "NNI port is configured as default from NB", log.Fields{"NB NNI Port": devConfig.UplinkPort, "SB NNI Ports": device.NniPort})
+ return nil // Match found
+ }
+ }
+ return fmt.Errorf("nni port mismatch: NB NNI Port: %s, SB NNI Ports: %v", devConfig.UplinkPort, device.NniPort)
+}
+
// AddSvc adds a service on the VNET on a port. The addition is
// triggered when NB requests for service addition
func (vpv *VoltPortVnet) AddSvc(cntx context.Context, svc *VoltService) {
@@ -1084,12 +1115,18 @@
return
}
- // If NNI port is not mached to nb nni port
- devConfig := GetApplication().GetDeviceConfig(voltDevice.SerialNum)
-
- if devConfig.UplinkPort != voltDevice.NniPort {
- logger.Errorw(ctx, "NNI port mismatch", log.Fields{"NB NNI Port": devConfig.UplinkPort, "SB NNI port": voltDevice.NniPort})
- return
+ if svc.NniPort != "" {
+ err := vpv.ValidateNniPort(voltDevice, svc.NniPort)
+ if err != nil {
+ logger.Warnw(ctx, "Not pushing service flows: NNI is not configured", log.Fields{"Port": vpv.Port, "Device": voltDevice.Name, "NNI": svc.NniPort, "Error": err})
+ return
+ }
+ } else {
+ nni, err := GetApplication().GetNniPort(voltDevice.Name)
+ if nni == "" {
+ logger.Warnw(ctx, "Not pushing service flows: Default NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": voltDevice.Name, "Error": err})
+ return
+ }
}
// Push Service Flows if DHCP relay is not configured
// or already DHCP flows are configured for the VPV
@@ -1332,6 +1369,90 @@
vpv.RangeOnServices(cntx, ClearServiceCounters, false)
}
+// BuildDefaultDhcpTrapFlow to build the downstream dhcp flows
+func (va *VoltApplication) BuildDefaultDhcpTrapFlow(ctx context.Context, device *VoltDevice, port string) (*of.VoltFlow, error) {
+ logger.Infow(ctx, "Building NNI DS DHCP flow", log.Fields{"Port": port, "device": device.Name})
+ flow := &of.VoltFlow{}
+ flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
+ subFlow := of.NewVoltSubFlow()
+ subFlow.SetTableID(0)
+
+ subFlow.SetUdpv4Match()
+ subFlow.SrcPort = 67
+ subFlow.DstPort = 68
+
+ nniport, err := GetApplication().GetPortID(port)
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch port id %d for nni : %w", nniport, err)
+ }
+ subFlow.SetInPort(nniport)
+ // PortName and PortID to be used for validation of port before flow pushing
+ flow.PortID = nniport
+ flow.PortName = port
+ allowTransparent := 0
+
+ ontEtherTypeClass := 0
+ vlanControl := OLTSVlan
+ uniVlan := of.VlanNone
+ cVlan := of.VlanNone
+
+ metadata := uint64(allowTransparent)<<56 | uint64(ontEtherTypeClass)<<36 | uint64(vlanControl)<<32 | uint64(uniVlan)<<16 | uint64(cVlan)
+ subFlow.SetTableMetadata(metadata)
+ subFlow.Priority = of.DhcpFlowPriority
+
+ subFlow.SetReportToController()
+ // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
+ subFlow.Cookie = uint64(cVlan)<<52 | uint64(nniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
+
+ flow.SubFlows[subFlow.Cookie] = subFlow
+ logger.Infow(ctx, "Built NNI DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
+
+ return flow, nil
+}
+
+// AddDefaultDhcpTrapFlow function pushes the default DHCP flows to the VOLTHA via the controller
+func (va *VoltApplication) AddDefaultDhcpTrapFlow(cntx context.Context, vd *VoltDevice, p *VoltPort) error {
+ if vd.GlobalDhcpFlowAdded {
+ logger.Info(ctx, "Global Dhcp flow already exists")
+ return nil
+ }
+
+ flows, err := va.BuildDefaultDhcpTrapFlow(cntx, vd, p.Name)
+ if err == nil {
+ if err1 := va.PushTrapFlows(cntx, vd, p.Name, flows); err1 != nil {
+ logger.Errorw(cntx, "Failure pushing nni trap flows", log.Fields{"device": vd.Name, "port": p.Name})
+ return fmt.Errorf("failed to push trap flow for nni : %s, error : %w", p.Name, err1)
+ }
+ } else {
+ logger.Errorw(cntx, "Failure building nni trap flows", log.Fields{"device": vd.Name, "port": p.Name})
+ return fmt.Errorf("failed to build trap flow for nni : %s, error : %w", p.Name, err)
+ }
+ p.NniDhcpTrapFlowAdded = true
+ if GetApplication().GetVendorID() != Radisys && va.IsDhcpTrapFlowAdded(cntx, vd) {
+ logger.Debugw(ctx, "Global DHCP trap flow set", log.Fields{"device": vd.Name})
+ vd.GlobalDhcpFlowAdded = true
+ }
+ return nil
+}
+
+func (va *VoltApplication) IsDhcpTrapFlowAdded(ctx context.Context, vd *VoltDevice) bool {
+ if len(vd.NniPort) == 0 {
+ return false
+ }
+ flag := true
+ for _, nniPort := range vd.NniPort {
+ if p := vd.GetPort(nniPort); p != nil {
+ if !p.NniDhcpTrapFlowAdded {
+ flag = false
+ }
+ } else {
+ flag = false
+ }
+ }
+
+ return flag
+}
+
// AddUsDhcpFlows pushes the DHCP flows to the VOLTHA via the controller
func (vpv *VoltPortVnet) AddUsDhcpFlows(cntx context.Context) error {
var vd *VoltDevice
@@ -1380,30 +1501,49 @@
err := errorCodes.ErrDeviceNotFound
return fmt.Errorf("ds dhcp flow push failed - device not found for Port %s, Svlan %d, Cvlan %d, UniVlan %d. Device %s : %w", vpv.Port, vpv.SVlan, vpv.CVlan, vpv.UniVlan, device, err)
}
+
if vd.GlobalDhcpFlowAdded {
logger.Info(ctx, "Global Dhcp flow already exists")
return nil
}
- flows, err := vpv.BuildDsDhcpFlows()
- if err == nil {
- if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
- // push ind here and procced
- statusCode, statusMessage := errorCodes.GetErrorInfo(err1)
- vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
- }
+ nniPorts := make([]string, 0)
+ vpv.services.Range(func(key, value interface{}) bool {
+ svc := value.(*VoltService)
+ logger.Infow(ctx, "Found service on the vpv", log.Fields{"Name": svc.Name, "NNIPort": svc.NniPort})
+ nniPorts = append(nniPorts, svc.NniPort)
+ return true
+ })
+
+ if len(nniPorts) == 0 {
+ vpv.BuildAndPushDSDhcpFlows(cntx, vd, "")
} else {
- logger.Errorw(ctx, "DS DHCP Flow Add Failed", log.Fields{"Reason": err.Error()})
- // send ind here and proceed
- statusCode, statusMessage := errorCodes.GetErrorInfo(err)
- vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
+ for _, nniPort := range nniPorts {
+ vpv.BuildAndPushDSDhcpFlows(cntx, vd, nniPort)
+ }
}
+
if GetApplication().GetVendorID() != Radisys {
vd.GlobalDhcpFlowAdded = true
}
return nil
}
+func (vpv *VoltPortVnet) BuildAndPushDSDhcpFlows(cntx context.Context, device *VoltDevice, nniPort string) {
+ var err error
+ var flows *of.VoltFlow
+ flows, err = vpv.BuildDsDhcpFlows(nniPort)
+ if err == nil {
+ if err1 := vpv.PushFlows(cntx, device, flows); err1 != nil {
+ statusCode, statusMessage := errorCodes.GetErrorInfo(err1)
+ vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
+ }
+ } else {
+ statusCode, statusMessage := errorCodes.GetErrorInfo(err)
+ vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
+ }
+}
+
// DelDhcpFlows deletes both US & DS DHCP flows applied for this Vnet instantiated on the port
func (vpv *VoltPortVnet) DelDhcpFlows(cntx context.Context) {
logger.Info(ctx, "Received Delete DHCP Flows")
@@ -1471,11 +1611,42 @@
func (vpv *VoltPortVnet) delDsDhcp4Flows(cntx context.Context, device *VoltDevice) error {
logger.Debugw(ctx, "Received DS Delete DHCP4 Flows", log.Fields{"DeviceName": device.Name})
- flows, err := vpv.BuildDsDhcpFlows()
- if err == nil {
- return vpv.RemoveFlows(cntx, device, flows)
+ nniPorts := make([]string, 0)
+ vpv.services.Range(func(key, value interface{}) bool {
+ svc := value.(*VoltService)
+ logger.Infow(ctx, "Found service on the vpv", log.Fields{"Name": svc.Name, "NNIPort": svc.NniPort})
+ nniPorts = append(nniPorts, svc.NniPort)
+ return true
+ })
+
+ if len(nniPorts) == 0 {
+ if err := vpv.BuildAndRemoveDSDhcpFlows(cntx, device, ""); err != nil {
+ return err
+ }
+ } else {
+ for _, nniPort := range nniPorts {
+ if err := vpv.BuildAndRemoveDSDhcpFlows(cntx, device, nniPort); err != nil {
+ return err
+ }
+ }
}
- return fmt.Errorf("DS DHCP Flow Delete Failed : %w", err)
+ return nil
+}
+
+func (vpv *VoltPortVnet) BuildAndRemoveDSDhcpFlows(cntx context.Context, device *VoltDevice, nniPort string) error {
+ var err error
+ var flows *of.VoltFlow
+ flows, err = vpv.BuildDsDhcpFlows(nniPort)
+ if err == nil {
+ if err1 := vpv.RemoveFlows(cntx, device, flows); err1 != nil {
+ logger.Errorw(ctx, "DS DHCP Flow Remove Failed", log.Fields{"Reason": err.Error()})
+ return fmt.Errorf("ds dhcp flow remove failed - Port %s, NNIPort %s, Svlan %d, Cvlan %d, UniVlan %d. Device %s : %w", vpv.Port, nniPort, vpv.SVlan, vpv.CVlan, vpv.UniVlan, vpv.Device, err)
+ }
+ } else {
+ logger.Errorw(ctx, "DS DHCP Flow Build Failed", log.Fields{"Reason": err.Error()})
+ return fmt.Errorf("ds dhcp flow build failed - Port %s, NNIPort %s, Svlan %d, Cvlan %d, UniVlan %d. Device %s : %w", vpv.Port, nniPort, vpv.SVlan, vpv.CVlan, vpv.UniVlan, vpv.Device, err)
+ }
+ return nil
}
/*
@@ -1752,8 +1923,8 @@
}
// BuildDsDhcpFlows to build the downstream dhcp flows
-func (vpv *VoltPortVnet) BuildDsDhcpFlows() (*of.VoltFlow, error) {
- logger.Infow(ctx, "Building DS DHCP flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
+func (vpv *VoltPortVnet) BuildDsDhcpFlows(nniPort string) (*of.VoltFlow, error) {
+ logger.Infow(ctx, "Building DS DHCP flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr, "NNIPort": nniPort})
flow := &of.VoltFlow{}
flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
subFlow := of.NewVoltSubFlow()
@@ -1766,15 +1937,28 @@
subFlow.SrcPort = 67
subFlow.DstPort = 68
uniport, _ := GetApplication().GetPortID(vpv.Port)
- nni, err := GetApplication().GetNniPort(vpv.Device)
+
+ device, err := GetApplication().GetDeviceFromPort(vpv.Port)
if err != nil {
- return nil, fmt.Errorf("failed to fetch nni port %s from vpv : %w", nni, err)
+ return nil, fmt.Errorf("error getting device for vpv %s and port %s : %w", vpv.VnetName, vpv.Port, err)
}
- nniport, err := GetApplication().GetPortID(nni)
- if err != nil {
- return nil, fmt.Errorf("failed to fetch port id %d for nni : %w", nniport, err)
+ var inport uint32
+ if nniPort != "" {
+ if nniPortID := device.GetPortIDFromPortName(nniPort); nniPortID != 0 {
+ inport = nniPortID
+ } else {
+ return nil, fmt.Errorf("error getting portID for NNI port %s : %w", nniPort, err)
+ }
+ } else {
+ nniPort, err := GetApplication().GetNniPort(device.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
+ return nil, err
+ }
+ inport, _ = GetApplication().GetPortID(nniPort)
}
- subFlow.SetInPort(nniport)
+
+ subFlow.SetInPort(inport)
// PortName and PortID to be used for validation of port before flow pushing
flow.PortID = uniport
flow.PortName = vpv.Port
@@ -2287,7 +2471,7 @@
if p != nil {
logger.Debugw(ctx, "Checking UNI port state", log.Fields{"State": p.State})
if d.State == controller.DeviceStateUP && p.State == PortStateUp {
- vpv.PortUpInd(cntx, d, port)
+ vpv.PortUpInd(cntx, d, port, vs.NniPort)
}
}
}
@@ -2384,7 +2568,7 @@
// If the port is NNI port, the services dont exist on it. The svc then
// must be obtained from a different context and is not included here
- if port == d.NniPort {
+ if d.IsPortNni(port) {
return nil
}
@@ -2449,7 +2633,7 @@
// If the port is NNI port, the services dont exist on it. The svc then
// must be obtained from a different context and is not included here
- if port == d.NniPort {
+ if d.IsPortNni(port) {
return nil, nil
}
@@ -2530,15 +2714,20 @@
logger.Warnw(ctx, "Configuring Dev Flows Group for device failed ", log.Fields{"Device": device.Name, "err": err})
return true
}
- if portID, err := va.GetPortID(device.NniPort); err == nil {
- if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
+ nniPort, err := GetApplication().GetNniPort(device.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
+ return true
+ }
+ if portID, err := va.GetPortID(nniPort); err == nil {
+ if state, _ := cntlr.GetController().GetPortState(device.Name, nniPort); state != cntlr.PortStateUp {
logger.Warnw(ctx, "Skipping Dev Flow Configuration - Port Down", log.Fields{"Device": device})
return true
}
// Pushing ICMPv6 Flow
flow := BuildICMPv6Flow(portID, vnet)
- err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
+ err = cntlr.GetController().AddFlows(cntx, nniPort, device.Name, flow)
if err != nil {
logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
return true
@@ -2547,7 +2736,7 @@
// Pushing ARP Flow
flow = BuildDSArpFlow(portID, vnet)
- err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
+ err = cntlr.GetController().AddFlows(cntx, nniPort, device.Name, flow)
if err != nil {
logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
return true
@@ -2563,6 +2752,11 @@
va.DevicesDisc.Range(pushflow)
}
+func (va *VoltApplication) PushTrapFlows(cntx context.Context, device *VoltDevice, nniPort string, flow *of.VoltFlow) error {
+ logger.Debugw(ctx, "Push NNI DHCP Trap Flows", log.Fields{"DeviceName": device.Name, "Flow port": flow.PortID})
+ return cntlr.GetController().AddFlows(cntx, nniPort, device.Name, flow)
+}
+
// PushDevFlowForDevice to push icmpv6 flows for device
func (va *VoltApplication) PushDevFlowForDevice(cntx context.Context, device *VoltDevice) {
logger.Debugw(ctx, "PushDevFlowForDevice", log.Fields{"device": device.Name})
@@ -2580,7 +2774,12 @@
logger.Infow(ctx, "Flow already pushed for these Vlans. Adding profile to list", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
return true
}
- nniPortID, err := va.GetPortID(device.NniPort)
+ nniPort, err := GetApplication().GetNniPort(device.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
+ return true
+ }
+ nniPortID, err := va.GetPortID(nniPort)
if err != nil {
logger.Errorw(ctx, "Push ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
}
@@ -2589,7 +2788,7 @@
return true
}
flow := BuildICMPv6Flow(nniPortID, vnet)
- err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
+ err = cntlr.GetController().AddFlows(cntx, nniPort, device.Name, flow)
if err != nil {
logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
return true
@@ -2597,7 +2796,7 @@
logger.Infow(ctx, "ICMP Flow Added to Queue", log.Fields{"flow": flow})
flow = BuildDSArpFlow(nniPortID, vnet)
- err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
+ err = cntlr.GetController().AddFlows(cntx, nniPort, device.Name, flow)
if err != nil {
logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
return true
@@ -2627,8 +2826,13 @@
return true
}
}
- if portID, err := va.GetPortID(device.NniPort); err == nil {
- if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
+ nniPort, err := GetApplication().GetNniPort(device.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
+ return true
+ }
+ if portID, err := va.GetPortID(nniPort); err == nil {
+ if state, _ := cntlr.GetController().GetPortState(device.Name, nniPort); state != cntlr.PortStateUp {
logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
return true
}
@@ -2676,7 +2880,12 @@
logger.Warnw(ctx, "ICMPv6 Flow map entry not found for Vnet", log.Fields{"Vnet": vnet.VnetConfig})
return true
}
- nniPortID, err := va.GetPortID(device.NniPort)
+ nniPort, err := GetApplication().GetNniPort(device.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
+ return true
+ }
+ nniPortID, err := va.GetPortID(nniPort)
if err != nil {
logger.Errorw(ctx, "Delete ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
}
@@ -2738,8 +2947,13 @@
logger.Warnw(ctx, "Dev Flow map entry not found for Vnet", log.Fields{"PodReboot": vgcRebooted, "VnetDeleteInProgress": vnet.DeleteInProgress})
return true
}
- if portID, err := va.GetPortID(device.NniPort); err == nil {
- if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
+ nniPort, err := GetApplication().GetNniPort(device.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
+ return true
+ }
+ if portID, err := va.GetPortID(nniPort); err == nil {
+ if state, _ := cntlr.GetController().GetPortState(device.Name, nniPort); state != cntlr.PortStateUp {
logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
return false
}
@@ -3023,7 +3237,12 @@
vv.PendingDeleteFlow[device.Name] = flowMap
}
vv.WriteToDb(cntx)
- return cntlr.GetController().DelFlows(cntx, device.NniPort, device.Name, flow, false)
+ nniPort, err := GetApplication().GetNniPort(device.Name)
+ if err != nil {
+ logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
+ return err
+ }
+ return cntlr.GetController().DelFlows(cntx, nniPort, device.Name, flow, false)
}
// CheckAndDeleteVnet - remove Vnet from DB is there are no pending flows to be removed
@@ -3116,7 +3335,7 @@
// If the port is NNI port, the services dont exist on it. The svc then
// must be obtained from a different context and is not included here
- if port == d.NniPort {
+ if d.IsPortNni(port) {
return nil
}
@@ -3246,17 +3465,19 @@
})
}
-func (vpv *VoltPortVnet) IsServiceActivated(cntx context.Context) bool {
+func (vpv *VoltPortVnet) IsServiceActivated(cntx context.Context) (bool, string) {
logger.Debugw(ctx, "Is Service Activated", log.Fields{"Name": vpv.Port})
isActivated := false
+ nniPort := ""
vpv.services.Range(func(key, value interface{}) bool {
svc := value.(*VoltService)
if svc.IsActivated {
logger.Infow(ctx, "Found activated service on the vpv", log.Fields{"Name": svc.Name})
isActivated = true
+ nniPort = svc.NniPort
return false //to exit loop
}
return true
})
- return isActivated
+ return isActivated, nniPort
}
diff --git a/internal/pkg/application/vnets_test.go b/internal/pkg/application/vnets_test.go
index d0f56ae..7016667 100644
--- a/internal/pkg/application/vnets_test.go
+++ b/internal/pkg/application/vnets_test.go
@@ -85,7 +85,7 @@
},
}
vpv.services.Store(test_device, voltServ)
- if got := vpv.IsServiceActivated(tt.args.cntx); got != tt.want {
+ if got, _ := vpv.IsServiceActivated(tt.args.cntx); got != tt.want {
t.Errorf("VoltPortVnet.IsServiceActivated() = %v, want %v", got, tt.want)
}
})
@@ -226,7 +226,7 @@
}
case "port == d.NniPort":
va.DevicesDisc.Store(test_device, voltDevice)
- voltDevice.NniPort = "test_port"
+ voltDevice.NniPort = []string{"test_port"}
if got := va.GetMatchingMcastService(tt.args.port, tt.args.device, tt.args.cvlan); !reflect.DeepEqual(got, tt.want) {
t.Errorf("VoltApplication.GetMatchingMcastService() = %v, want %v", got, tt.want)
}
@@ -621,7 +621,7 @@
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
State: cntlr.DeviceStateUP,
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
Ports: sync.Map{},
FlowDelEventMap: util.NewConcurrentMap(),
ConfiguredVlanForDeviceFlows: util.NewConcurrentMap(),
@@ -780,7 +780,7 @@
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
State: cntlr.DeviceStateUP,
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
FlowDelEventMap: util.NewConcurrentMap(),
ConfiguredVlanForDeviceFlows: util.NewConcurrentMap(),
icmpv6GroupAdded: true,
@@ -906,7 +906,7 @@
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
State: cntlr.DeviceStateUP,
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
FlowDelEventMap: util.NewConcurrentMap(),
ConfiguredVlanForDeviceFlows: util.NewConcurrentMap(),
icmpv6GroupAdded: true,
@@ -1013,7 +1013,7 @@
device: &VoltDevice{
Name: test_device,
ConfiguredVlanForDeviceFlows: util.NewConcurrentMap(),
- NniPort: "test_nni_port",
+ NniPort: []string{"test_nni_port"},
},
},
},
@@ -1024,7 +1024,7 @@
device: &VoltDevice{
Name: test_device,
ConfiguredVlanForDeviceFlows: util.NewConcurrentMap(),
- NniPort: "test_nni_port",
+ NniPort: []string{"test_nni_port"},
VlanPortStatus: sync.Map{},
},
},
@@ -1771,7 +1771,7 @@
vpv.Device = deviceName
voltDev.State = cntlr.DeviceStateUP
voltDev.GlobalDhcpFlowAdded = false
- voltDev.NniPort = "16777472"
+ voltDev.NniPort = []string{"16777472"}
va.PortsDisc.Store("16777472", voltPort)
appMock := mocks.NewMockApp(gomock.NewController(t))
cntlr.NewController(ctx, appMock)
@@ -1798,7 +1798,7 @@
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
State: cntlr.DeviceStateUP,
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
FlowAddEventMap: util.NewConcurrentMap(),
}
va.DevicesDisc.Store("SDX6320031", voltDev)
@@ -1893,7 +1893,7 @@
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
State: cntlr.DeviceStateUP,
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
FlowAddEventMap: util.NewConcurrentMap(),
}
voltPort := &VoltPort{
@@ -2059,12 +2059,20 @@
UniVlan: of.VlanAny,
},
}
+ deviceConfig := &DeviceConfig{
+ SerialNumber: "SDX6320031",
+ HardwareIdentifier: "dummy_hardware_identifier",
+ IPAddress: "10.9.8.7",
+ UplinkPort: "16777216",
+ NasID: "nas_id",
+ NniDhcpTrapVid: 123,
+ }
voltDev := &VoltDevice{
Name: "49686e2d-618f-4e8e-bca0-442ab850a63a",
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
State: cntlr.DeviceStateUP,
- NniPort: "16777216",
+ NniPort: []string{"16777472"},
Ports: sync.Map{},
}
tests := []struct {
@@ -2116,7 +2124,9 @@
}
assert.NotNil(t, got)
case "BuildDsDhcp6Flows":
+ voltDev.NniPort = []string{"16777216"}
va.DevicesDisc.Store("SDX6320031", voltDev)
+ va.DevicesConfig.Store("SDX6320031", deviceConfig)
got, err := vpv.BuildDsDhcp6Flows()
if (err != nil) != tt.wantErr {
t.Errorf("VoltPortVnet.BuildDsDhcp6Flows() error = %v, wantErr %v", err, tt.wantErr)
@@ -2140,7 +2150,7 @@
}
assert.Nil(t, got)
case "BuildDsDhcp6Flows_portnotfound":
- voltDev.NniPort = "abc"
+ voltDev.NniPort = []string{"abc"}
got, err := vpv.BuildDsDhcp6Flows()
if (err != nil) != tt.wantErr {
t.Errorf("VoltPortVnet.BuildDsDhcp6Flows_portnotfound() error = %v, wantErr %v", err, tt.wantErr)
@@ -2447,7 +2457,7 @@
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
State: cntlr.DeviceStateUP,
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
Ports: sync.Map{},
FlowDelEventMap: util.NewConcurrentMap(),
}
@@ -2524,7 +2534,7 @@
SerialNum: "SDX6320031",
NniDhcpTrapVid: 123,
State: cntlr.DeviceStateUP,
- NniPort: "16777472",
+ NniPort: []string{"16777472"},
Ports: sync.Map{},
FlowDelEventMap: util.NewConcurrentMap(),
ConfiguredVlanForDeviceFlows: util.NewConcurrentMap(),
diff --git a/internal/pkg/util/utils.go b/internal/pkg/util/utils.go
index 36aab0b..9b22576 100644
--- a/internal/pkg/util/utils.go
+++ b/internal/pkg/util/utils.go
@@ -146,9 +146,22 @@
}
// GetUniPortFromFlow returns uni port from the flow data
-func GetUniPortFromFlow(nniPort string, flow *of.VoltSubFlow) uint32 {
+func GetUniPortFromFlow(uplinkPort string, nniPorts []string, flow *of.VoltSubFlow) uint32 {
var portNo uint32
- if nniPort == strconv.Itoa(int(flow.Match.InPort)) {
+ var isDSFlow bool
+
+ if len(nniPorts) > 0 {
+ for _, nniPort := range nniPorts {
+ if nniPort == strconv.Itoa(int(flow.Match.InPort)) {
+ isDSFlow = true
+ break
+ }
+ }
+ } else if uplinkPort == strconv.Itoa(int(flow.Match.InPort)) {
+ isDSFlow = true
+ }
+
+ if isDSFlow {
if of.IPProtocolUDP == flow.Match.L4Protocol {
// For DHCP DS flow, uniport is not part of metadata. Hence retrieve it from cookie
portNo = GetUniFromDSDhcpFlow(flow.Cookie)
@@ -158,6 +171,7 @@
} else {
portNo = flow.Match.InPort
}
+
return portNo
}
diff --git a/voltha-go-controller/nbi/subscriber.go b/voltha-go-controller/nbi/subscriber.go
index f42f109..31410ae 100644
--- a/voltha-go-controller/nbi/subscriber.go
+++ b/voltha-go-controller/nbi/subscriber.go
@@ -135,14 +135,7 @@
var voltAppIntr app.VoltAppInterface
voltApp := app.GetApplication()
voltAppIntr = voltApp
- if len(srvInfo.UniTagList) == 0 {
- logger.Infow(ctx, "Received OLT configuration", log.Fields{"req": srvInfo})
- err := voltAppIntr.AddDeviceConfig(cntx, srvInfo.ID, srvInfo.HardwareIdentifier, srvInfo.NasID, srvInfo.IPAddress, srvInfo.UplinkPort, srvInfo.NniDhcpTrapVid)
- if err != nil {
- logger.Warnw(ctx, "Device config addition failed :", log.Fields{"req": srvInfo, "Reason": err.Error()})
- }
- return
- }
+
for _, uniTagInfo := range srvInfo.UniTagList {
var vs app.VoltServiceCfg
@@ -154,6 +147,7 @@
vs.Name = svcname + strconv.Itoa(uniTagInfo.TechnologyProfileID)
vs.Port = srvInfo.NasPortID
+ vs.NniPort = srvInfo.UplinkPort
vs.SVlan = of.VlanType(uniTagInfo.PonSTag)
vs.CVlan = of.VlanType(uniTagInfo.PonCTag)
vs.UniVlan = of.VlanType(uniTagInfo.UniTagMatch)