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