VOL-291 : PON simulator refactoring for cluster integration
- Added ponsim build target in Makefile
- Added new option to vcore to select comm type with ponsim
- Modified all proto files to include destination go package
Amendments:
- Clean up based on review comments
- Properly close GRPC connections in ponsim_olt adapter
- Added voltha namespace to some k8s templates
Change-Id: I2f349fa7b3550a8a8cc8fc676cc896f33fbb9372
diff --git a/ponsim/v2/core/ponsim_alarm.go b/ponsim/v2/core/ponsim_alarm.go
new file mode 100644
index 0000000..e99b84d
--- /dev/null
+++ b/ponsim/v2/core/ponsim_alarm.go
@@ -0,0 +1,175 @@
+package core
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/opencord/voltha/ponsim/v2/common"
+ "github.com/opencord/voltha/protos/go/voltha"
+ "github.com/sirupsen/logrus"
+ "math/rand"
+ "net"
+ "time"
+)
+
+// TODO: user-defined values? min/max intervals, vlan?
+
+const (
+ minInterval = 20
+ maxInterval = 60
+ vlandId = 4000
+ localhost = "127.0.0.1"
+ ttl = 64
+ ipVersion = 4
+)
+
+type Alarm struct {
+ Severity int `json:"severity"`
+ Type int `json:"type"`
+ Category int `json:"category"`
+ State int `json:"state"`
+ TimeStamp int `json:"ts"`
+ Description string `json:"description"`
+}
+
+/*
+PonSimAlarm is the structure responsible for the handling of alarms
+*/
+type PonSimAlarm struct {
+ forwardFunction func(int, gopacket.Packet)
+ dstInterface string
+ dstEndpoint string
+}
+
+/*
+NewPonSimAlarm instantiates a new alarm handling structure
+*/
+func NewPonSimAlarm(dstInterface string, dstEndpoint string, function func(int, gopacket.Packet)) *PonSimAlarm {
+ psa := &PonSimAlarm{dstInterface: dstInterface, dstEndpoint: dstEndpoint, forwardFunction: function}
+ return psa
+}
+
+/*
+prepareAlarm constructs an alarm object with random field values.
+*/
+func (a *PonSimAlarm) prepareAlarm() *Alarm {
+ alarm_severity := rand.Intn(len(voltha.AlarmEventSeverity_AlarmEventSeverity_value))
+ alarm_type := rand.Intn(len(voltha.AlarmEventType_AlarmEventType_value))
+ alarm_category := rand.Intn(len(voltha.AlarmEventCategory_AlarmEventCategory_value))
+ alarm_state := int(voltha.AlarmEventState_RAISED)
+ alarm_ts := time.Now().UTC().Second()
+ alarm_description := fmt.Sprintf("%s.%s alarm",
+ voltha.AlarmEventType_AlarmEventType_name[int32(alarm_type)],
+ voltha.AlarmEventCategory_AlarmEventCategory_name[int32(alarm_category)],
+ )
+
+ alarm := &Alarm{
+ Severity: alarm_severity,
+ Type: alarm_type,
+ Category: alarm_category,
+ State: alarm_state,
+ TimeStamp: alarm_ts,
+ Description: alarm_description,
+ }
+
+ return alarm
+}
+
+/*
+sendAlarm constructs and forwards the alarm to the network
+*/
+func (a *PonSimAlarm) sendAlarm(alarm *Alarm) {
+ // Ethernet layer is configured as a broadcast packet
+ ethLayer := &layers.Ethernet{
+ SrcMAC: common.GetMacAddress(a.dstInterface),
+ DstMAC: layers.EthernetBroadcast,
+ EthernetType: layers.EthernetTypeDot1Q,
+ }
+
+ // Need to encapsulate in VLAN so that voltha captures the packet
+ dot1qLayer := &layers.Dot1Q{
+ Type: layers.EthernetTypeIPv4,
+ VLANIdentifier: vlandId,
+ }
+
+ common.Logger().WithFields(logrus.Fields{
+ "Alarm": a,
+ "srcIp": common.GetInterfaceIP(a.dstInterface),
+ "dstIp": common.GetHostIP(a.dstEndpoint),
+ }).Info("SRC/DST IP addresses")
+
+ // IP layer needs the following attributes at a minimum in order to have
+ // a properly formed packet
+ ipLayer := &layers.IPv4{
+ SrcIP: net.ParseIP(common.GetInterfaceIP(a.dstInterface)),
+ DstIP: net.ParseIP(common.GetHostIP(a.dstEndpoint)),
+ //SrcIP: net.ParseIP(localhost),
+ //DstIP: net.ParseIP(localhost),
+ Version: ipVersion,
+ TTL: ttl,
+ Protocol: layers.IPProtocolTCP,
+ }
+
+ // TCP layer does not require anything special
+ // except than providing the IP layer so that the checksum can be
+ // properly calculated
+ tcpLayer := &layers.TCP{}
+ tcpLayer.SetNetworkLayerForChecksum(ipLayer)
+
+ // Convert the alarm to bytes to include it as the packet payload
+ rawData, _ := json.Marshal(alarm)
+
+ // Construct the packet
+ buffer := gopacket.NewSerializeBuffer()
+ options := gopacket.SerializeOptions{
+ FixLengths: true,
+ ComputeChecksums: true,
+ }
+ gopacket.SerializeLayers(buffer, options,
+ ethLayer,
+ dot1qLayer,
+ ipLayer,
+ tcpLayer,
+ gopacket.Payload(rawData),
+ )
+ frame := gopacket.NewPacket(
+ buffer.Bytes(),
+ layers.LayerTypeEthernet,
+ gopacket.Default,
+ )
+
+ // Forward the packetized alarm to the network
+ a.forwardFunction(0, frame)
+
+ common.Logger().WithFields(logrus.Fields{
+ "Alarm": alarm,
+ "Frame": frame.Dump(),
+ }).Debug("Sent alarm")
+}
+
+/*
+raiseAlarm submits an alarm object with a RAISED state
+*/
+func (a *PonSimAlarm) raiseAlarm(alarm *Alarm) {
+ alarm.State = int(voltha.AlarmEventState_RAISED)
+ a.sendAlarm(alarm)
+}
+
+/*
+clearAlarm submits an alarm object with a CLEARED state
+*/
+func (a *PonSimAlarm) clearAlarm(alarm *Alarm) {
+ alarm.State = int(voltha.AlarmEventState_CLEARED)
+ a.sendAlarm(alarm)
+}
+
+/*
+GenerateAlarm simulates RAISE and CLEAR alarm events with a random delay in between each state.
+*/
+func (a *PonSimAlarm) GenerateAlarm() {
+ alarm := a.prepareAlarm()
+ a.raiseAlarm(alarm)
+ time.Sleep(time.Duration(rand.Intn(maxInterval-minInterval)+minInterval) * time.Second)
+ a.clearAlarm(alarm)
+}