[VOL-4814] Adding Rest interfaces for flow and subscribers
Change-Id: I7da50b14e7600884a8b38c37b63704241942d8af
diff --git a/internal/pkg/application/application.go b/internal/pkg/application/application.go
index e7d2d04..04f4a6a 100644
--- a/internal/pkg/application/application.go
+++ b/internal/pkg/application/application.go
@@ -1283,12 +1283,17 @@
for _, vpv := range vpvs.([]*VoltPortVnet) {
vpv.VpvLock.Lock()
-
- //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)
+ //If no service is activated drop the portUpInd
+ if vpv.IsServiceActivated(cntx) {
+ //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)
+ }
+ } else {
+ // Service not activated, still attach device to service
+ vpv.setDevice(d.Name)
}
vpv.VpvLock.Unlock()
}
diff --git a/internal/pkg/application/dhcprelay.go b/internal/pkg/application/dhcprelay.go
index b779f1f..dd92383 100644
--- a/internal/pkg/application/dhcprelay.go
+++ b/internal/pkg/application/dhcprelay.go
@@ -21,6 +21,7 @@
"errors"
"net"
"sync"
+ "time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
@@ -1342,3 +1343,53 @@
func init() {
dhcpNws = NewDhcpNetworks()
}
+
+type DhcpAllocation struct {
+ SubscriberID string `json:"subscriberId"`
+ ConnectPoint string `json:"connectPoint"`
+ MacAddress net.HardwareAddr `json:"macAddress"`
+ State int `json:"state"`
+ VlanID int `json:"vlanId"`
+ CircuitID []byte `json:"circuitId"`
+ IpAllocated net.IP `json:"ipAllocated"`
+ AllocationTimeStamp time.Time `json:"allocationTimestamp"`
+}
+
+// GetAllocations returns DhcpAllocation info for all devices or for a device ID
+func (va *VoltApplication) GetAllocations(cntx context.Context, deviceID string) ([]*DhcpAllocation, error) {
+ logger.Debugw(ctx, "GetAllocations", log.Fields{"DeviceID": deviceID})
+ var allocations []*DhcpAllocation
+ for _, drv := range dhcpNws.Networks {
+ drv.sessionLock.RLock()
+ for _, session := range drv.sessions {
+ vpv, ok := session.(*VoltPortVnet)
+ if ok {
+ var subscriber string
+ // return Name of first service
+ vpv.services.Range(func(key, value interface{}) bool {
+ svc := value.(*VoltService)
+ subscriber = svc.Name
+ return false
+ })
+ // If deviceID is not provided, return all allocations
+ // If deviceID exists then filter on deviceID
+ if len(deviceID) == 0 || deviceID == vpv.Device {
+ allocation := &DhcpAllocation {
+ SubscriberID : subscriber,
+ ConnectPoint : vpv.Device,
+ MacAddress : vpv.MacAddr,
+ State : int(vpv.RelayState) ,
+ VlanID : int(vpv.SVlan) ,
+ CircuitID : vpv.CircuitID ,
+ IpAllocated : vpv.Ipv4Addr ,
+ AllocationTimeStamp : vpv.DhcpExpiryTime,
+ }
+ logger.Debugw(ctx, "DHCP Allocation found", log.Fields{"DhcpAlloc": allocation})
+ allocations = append(allocations, allocation)
+ }
+ }
+ }
+ drv.sessionLock.RUnlock()
+ }
+ return allocations, nil
+}
diff --git a/internal/pkg/application/service.go b/internal/pkg/application/service.go
index 690f348..af903af 100644
--- a/internal/pkg/application/service.go
+++ b/internal/pkg/application/service.go
@@ -42,6 +42,8 @@
const (
// DSLAttrEnabled constant
DSLAttrEnabled string = "ENABLED"
+ // DeviceAny constant
+ DeviceAny string = "DEVICE-ANY"
)
// VoltServiceCfg structure
@@ -95,7 +97,7 @@
MinDataRateDs uint32
MaxDataRateUs uint32
MaxDataRateDs uint32
-
+ IsActivated bool
Trigger ServiceTrigger
}
@@ -717,9 +719,10 @@
subflow1.SetGoToTable(1)
subflow1.SetInPort(inport)
+ /*
if pbits != PbitMatchNone {
subflow1.SetMatchPbit(pbits)
- }
+ }*/
if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
return nil, err
}
@@ -2005,3 +2008,124 @@
},
})
}
+
+// GetProgrammedSubscribers to get list of programmed subscribers
+func (va *VoltApplication) GetProgrammedSubscribers (cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
+ var svcList []*VoltService
+ logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
+ va.ServiceByName.Range(func(key, value interface{}) bool {
+ vs := value.(*VoltService)
+ if (len(deviceID) > 0 ) {
+ if (len(portNo) > 0) {
+ if deviceID == vs.Device && portNo == vs.Port {
+ svcList = append(svcList, vs)
+ }
+ } else {
+ if deviceID == vs.Device {
+ svcList = append(svcList, vs)
+ }
+ }
+ } else {
+ svcList = append(svcList, vs)
+ }
+ return true
+ })
+ return svcList, nil
+}
+
+// ActivateService to activate pre-provisioned service
+func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) {
+ logger.Infow(ctx, "Service Activate Request ", log.Fields{"Device": deviceID, "Port": portNo})
+ va.ServiceByName.Range(func(key, value interface{}) bool {
+ vs := value.(*VoltService)
+ // If device id is not provided check only port number
+ if deviceID == DeviceAny {
+ deviceID = vs.Device
+ }
+ // If svlan if provided, then the tags and tpID of service has to be matching
+ if (sVlan != of.VlanNone && ( sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) ) {
+ return true
+ }
+ if portNo == vs.Port && !vs.IsActivated {
+ d := va.GetDevice(deviceID)
+ if d == nil {
+ logger.Warnw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
+ return true
+ }
+ p := d.GetPort(vs.Port)
+ if p == nil {
+ logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
+ return true
+ }
+ logger.Infow(ctx, "Service Activate", log.Fields{"Name": vs.Name})
+ vs.IsActivated = true
+ va.ServiceByName.Store(vs.Name, vs)
+ vs.WriteToDb(cntx)
+ // If port is already up send indication to vpv
+ 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, d, portNo)
+ } else {
+ logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
+ }
+ }
+ }
+ return true
+ })
+}
+
+// DeactivateService to activate pre-provisioned service
+func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) {
+ logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
+ va.ServiceByName.Range(func(key, value interface{}) bool {
+ vs := value.(*VoltService)
+ // If svlan if provided, then the tags and tpID of service has to be matching
+ if (sVlan != of.VlanNone && ( sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) ) {
+ return true
+ }
+ // If device id is not provided check only port number
+ if deviceID == DeviceAny {
+ deviceID = vs.Device
+ }
+ if deviceID == vs.Device && portNo == vs.Port && vs.IsActivated {
+ vs.IsActivated = false
+ va.ServiceByName.Store(vs.Name, vs)
+ vs.WriteToDb(cntx)
+ d := va.GetDevice(deviceID)
+ if d == nil {
+ logger.Warnw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
+ return true
+ }
+ p := d.GetPort(vs.Port)
+ if p != nil && p.State == PortStateUp {
+ if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
+ // Port down call internally deletes all the flows
+ vpv.PortDownInd(cntx, deviceID, portNo)
+ if vpv.IgmpEnabled {
+ va.ReceiverDownInd(cntx, deviceID, portNo)
+ }
+ } else {
+ logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
+ }
+ }
+ }
+ return true
+ })
+}
+
+/* GetServicePbit to get first set bit in the pbit map
+ returns -1 : If configured to match on all pbits
+ returns 8 : If no pbits are configured
+ returns first pbit if specific pbit is configured */
+func (vs *VoltService) GetServicePbit() int {
+ if vs.IsPbitExist(of.PbitMatchAll) {
+ return -1
+ }
+ for pbit:= 0; pbit < int(of.PbitMatchNone); pbit++ {
+ if vs.IsPbitExist(of.PbitType(pbit)) {
+ return pbit
+ }
+ }
+ return int(of.PbitMatchNone)
+}
diff --git a/internal/pkg/application/vnets.go b/internal/pkg/application/vnets.go
index e11960c..85de6dc 100644
--- a/internal/pkg/application/vnets.go
+++ b/internal/pkg/application/vnets.go
@@ -513,7 +513,7 @@
vpv.printAssociatedVPVs(false)
}
- logger.Infow(ctx, "Associating VPV and Device", log.Fields{"Device": vpv.Device, "Port": vpv.Port, "SVlan": vpv.SVlan})
+ logger.Infow(ctx, "Associating VPV and Device", log.Fields{"Device": device, "Port": vpv.Port, "SVlan": vpv.SVlan})
vpv.Device = device
GetApplication().AssociateVpvsToDevice(device, vpv)
@@ -1036,7 +1036,10 @@
//TODO-COMM: vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
return
}
-
+ if !svc.IsActivated {
+ logger.Warn(ctx, "Not pushing Service Flows: Service Not activated")
+ return
+ }
//Push Service Flows if DHCP relay is not configured
//or already DHCP flows are configured for the VPV
//to which the serivce is associated
@@ -2244,6 +2247,17 @@
// Add the service that is causing the VNET to be added to the port
vpv.AddSvc(cntx, vs)
+ if !vs.IsActivated {
+ logger.Warn(ctx, "Not Checking port state: Service Not activated")
+ // Process the PORT UP if the port is already up
+ d, err := va.GetDeviceFromPort(port)
+ if err == nil {
+ vpv.setDevice(d.Name)
+ }
+ vpv.WriteToDb(cntx)
+ return vpv
+ }
+
// Process the PORT UP if the port is already up
d, err := va.GetDeviceFromPort(port)
if err == nil {
@@ -3206,3 +3220,17 @@
DhcpPbit: vpv.DhcpPbit,
})
}
+
+func (vpv *VoltPortVnet) IsServiceActivated(cntx context.Context) bool {
+ isActivated := false
+ 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
+ return false //to exit loop
+ }
+ return true
+ })
+ return isActivated
+}