blob: e99b84d84827a361d24042b41f77b25b9d44c2ce [file] [log] [blame]
Stephane Barbarie35595062018-02-08 08:34:39 -05001package core
2
3import (
4 "encoding/json"
5 "fmt"
6 "github.com/google/gopacket"
7 "github.com/google/gopacket/layers"
8 "github.com/opencord/voltha/ponsim/v2/common"
9 "github.com/opencord/voltha/protos/go/voltha"
10 "github.com/sirupsen/logrus"
11 "math/rand"
12 "net"
13 "time"
14)
15
16// TODO: user-defined values? min/max intervals, vlan?
17
18const (
19 minInterval = 20
20 maxInterval = 60
21 vlandId = 4000
22 localhost = "127.0.0.1"
23 ttl = 64
24 ipVersion = 4
25)
26
27type Alarm struct {
28 Severity int `json:"severity"`
29 Type int `json:"type"`
30 Category int `json:"category"`
31 State int `json:"state"`
32 TimeStamp int `json:"ts"`
33 Description string `json:"description"`
34}
35
36/*
37PonSimAlarm is the structure responsible for the handling of alarms
38*/
39type PonSimAlarm struct {
40 forwardFunction func(int, gopacket.Packet)
41 dstInterface string
42 dstEndpoint string
43}
44
45/*
46NewPonSimAlarm instantiates a new alarm handling structure
47*/
48func NewPonSimAlarm(dstInterface string, dstEndpoint string, function func(int, gopacket.Packet)) *PonSimAlarm {
49 psa := &PonSimAlarm{dstInterface: dstInterface, dstEndpoint: dstEndpoint, forwardFunction: function}
50 return psa
51}
52
53/*
54prepareAlarm constructs an alarm object with random field values.
55*/
56func (a *PonSimAlarm) prepareAlarm() *Alarm {
57 alarm_severity := rand.Intn(len(voltha.AlarmEventSeverity_AlarmEventSeverity_value))
58 alarm_type := rand.Intn(len(voltha.AlarmEventType_AlarmEventType_value))
59 alarm_category := rand.Intn(len(voltha.AlarmEventCategory_AlarmEventCategory_value))
60 alarm_state := int(voltha.AlarmEventState_RAISED)
61 alarm_ts := time.Now().UTC().Second()
62 alarm_description := fmt.Sprintf("%s.%s alarm",
63 voltha.AlarmEventType_AlarmEventType_name[int32(alarm_type)],
64 voltha.AlarmEventCategory_AlarmEventCategory_name[int32(alarm_category)],
65 )
66
67 alarm := &Alarm{
68 Severity: alarm_severity,
69 Type: alarm_type,
70 Category: alarm_category,
71 State: alarm_state,
72 TimeStamp: alarm_ts,
73 Description: alarm_description,
74 }
75
76 return alarm
77}
78
79/*
80sendAlarm constructs and forwards the alarm to the network
81*/
82func (a *PonSimAlarm) sendAlarm(alarm *Alarm) {
83 // Ethernet layer is configured as a broadcast packet
84 ethLayer := &layers.Ethernet{
85 SrcMAC: common.GetMacAddress(a.dstInterface),
86 DstMAC: layers.EthernetBroadcast,
87 EthernetType: layers.EthernetTypeDot1Q,
88 }
89
90 // Need to encapsulate in VLAN so that voltha captures the packet
91 dot1qLayer := &layers.Dot1Q{
92 Type: layers.EthernetTypeIPv4,
93 VLANIdentifier: vlandId,
94 }
95
96 common.Logger().WithFields(logrus.Fields{
97 "Alarm": a,
98 "srcIp": common.GetInterfaceIP(a.dstInterface),
99 "dstIp": common.GetHostIP(a.dstEndpoint),
100 }).Info("SRC/DST IP addresses")
101
102 // IP layer needs the following attributes at a minimum in order to have
103 // a properly formed packet
104 ipLayer := &layers.IPv4{
105 SrcIP: net.ParseIP(common.GetInterfaceIP(a.dstInterface)),
106 DstIP: net.ParseIP(common.GetHostIP(a.dstEndpoint)),
107 //SrcIP: net.ParseIP(localhost),
108 //DstIP: net.ParseIP(localhost),
109 Version: ipVersion,
110 TTL: ttl,
111 Protocol: layers.IPProtocolTCP,
112 }
113
114 // TCP layer does not require anything special
115 // except than providing the IP layer so that the checksum can be
116 // properly calculated
117 tcpLayer := &layers.TCP{}
118 tcpLayer.SetNetworkLayerForChecksum(ipLayer)
119
120 // Convert the alarm to bytes to include it as the packet payload
121 rawData, _ := json.Marshal(alarm)
122
123 // Construct the packet
124 buffer := gopacket.NewSerializeBuffer()
125 options := gopacket.SerializeOptions{
126 FixLengths: true,
127 ComputeChecksums: true,
128 }
129 gopacket.SerializeLayers(buffer, options,
130 ethLayer,
131 dot1qLayer,
132 ipLayer,
133 tcpLayer,
134 gopacket.Payload(rawData),
135 )
136 frame := gopacket.NewPacket(
137 buffer.Bytes(),
138 layers.LayerTypeEthernet,
139 gopacket.Default,
140 )
141
142 // Forward the packetized alarm to the network
143 a.forwardFunction(0, frame)
144
145 common.Logger().WithFields(logrus.Fields{
146 "Alarm": alarm,
147 "Frame": frame.Dump(),
148 }).Debug("Sent alarm")
149}
150
151/*
152raiseAlarm submits an alarm object with a RAISED state
153*/
154func (a *PonSimAlarm) raiseAlarm(alarm *Alarm) {
155 alarm.State = int(voltha.AlarmEventState_RAISED)
156 a.sendAlarm(alarm)
157}
158
159/*
160clearAlarm submits an alarm object with a CLEARED state
161*/
162func (a *PonSimAlarm) clearAlarm(alarm *Alarm) {
163 alarm.State = int(voltha.AlarmEventState_CLEARED)
164 a.sendAlarm(alarm)
165}
166
167/*
168GenerateAlarm simulates RAISE and CLEAR alarm events with a random delay in between each state.
169*/
170func (a *PonSimAlarm) GenerateAlarm() {
171 alarm := a.prepareAlarm()
172 a.raiseAlarm(alarm)
173 time.Sleep(time.Duration(rand.Intn(maxInterval-minInterval)+minInterval) * time.Second)
174 a.clearAlarm(alarm)
175}