blob: 8c5d9363f490860b12ce19cca550c3c23ab18cbe [file] [log] [blame]
Zdravko Bozakov958d81c2019-12-13 22:09:48 +01001/*
2 * Copyright 2018-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 */
16
17package sadis
18
19import (
20 "encoding/json"
21 "net/http"
22 "strings"
23 "sync"
24
25 "github.com/gorilla/mux"
26 "github.com/opencord/bbsim/internal/bbsim/devices"
27 "github.com/opencord/bbsim/internal/common"
28 log "github.com/sirupsen/logrus"
29)
30
31var sadisLogger = log.WithFields(log.Fields{
32 "module": "SADIS",
33})
34
35type sadisServer struct {
36 olt *devices.OltDevice
37}
38
39// bandwidthProfiles contains some dummy profiles
40var bandwidthProfiles = []interface{}{
41 &SadisBWPEntry{ID: "User_Bandwidth1", AIR: 100000, CBS: 10000, CIR: 30000, EBS: 1000, EIR: 20000},
42 &SadisBWPEntry{ID: "User_Bandwidth2", AIR: 100000, CBS: 5000, CIR: 100000, EBS: 5000, EIR: 1000000},
43 &SadisBWPEntry{ID: "User_Bandwidth3", AIR: 100000, CBS: 5000, CIR: 100000, EBS: 5000, EIR: 1000000},
44 &SadisBWPEntry{ID: "Default", AIR: 100000, CBS: 30, CIR: 600, EBS: 30, EIR: 400},
45}
46
47// SadisConfig is the top-level SADIS configuration struct
48type SadisConfig struct {
49 Sadis SadisEntries `json:"sadis"`
50 BandwidthProfile BandwidthProfileEntries `json:"bandwidthprofile"`
51}
52
53type SadisEntries struct {
54 Integration SadisIntegration `json:"integration"`
55 Entries []interface{} `json:"entries,omitempty"`
56}
57type BandwidthProfileEntries struct {
58 Integration SadisIntegration `json:"integration"`
59 Entries []interface{} `json:"entries,omitempty"`
60}
61
62type SadisIntegration struct {
63 URL string `json:"url,omitempty"`
64 Cache struct {
65 Enabled bool `json:"enabled"`
66 MaxSize int `json:"maxsize"`
67 TTL string `json:"ttl"`
68 } `json:"cache"`
69}
70
71type SadisOltEntry struct {
72 ID string `json:"id"`
73 HardwareIdentifier string `json:"hardwareIdentifier"`
74 IPAddress string `json:"ipAddress"`
75 NasID string `json:"nasId"`
76 UplinkPort int `json:"uplinkPort"`
77}
78
79type SadisOnuEntry struct {
80 ID string `json:"id"`
81 CTag int `json:"cTag"`
82 STag int `json:"sTag"`
83 NasPortID string `json:"nasPortId"`
84 CircuitID string `json:"circuitId"`
85 RemoteID string `json:"remoteId"`
86 TechnologyProfileID int `json:"technologyProfileId"`
87 UpstreamBandwidthProfile string `json:"upstreamBandwidthProfile"`
88 DownstreamBandwidthProfile string `json:"downstreamBandwidthProfile"`
89}
90
91// SADIS BandwithProfile Entry
92type SadisBWPEntry struct {
93 ID string `json:"id"`
94 AIR int `json:"air"`
95 CBS int `json:"cbs"`
96 CIR int `json:"cir"`
97 EBS int `json:"ebs"`
98 EIR int `json:"eir"`
99}
100
101// GetSadisConfig returns a full SADIS configuration struct ready to be marshalled into JSON
102func GetSadisConfig(olt *devices.OltDevice) *SadisConfig {
103 sadisEntries, _ := GetSadisEntries(olt)
104 bwpEntries := getBWPEntries()
105
106 conf := &SadisConfig{}
107 conf.Sadis = *sadisEntries
108 conf.BandwidthProfile = *bwpEntries
109
110 return conf
111}
112
113func GetSadisEntries(olt *devices.OltDevice) (*SadisEntries, error) {
114 solt, _ := GetOltEntry(olt)
115
116 entries := []interface{}{}
117 entries = append(entries, solt)
118
119 a := strings.Split(common.Options.BBSim.SadisRestAddress, ":")
120 port := a[len(a)-1]
121
122 integration := SadisIntegration{}
123 integration.URL = "http://bbsim:" + port + "/subscribers/%s"
124 integration.Cache.Enabled = false
125 integration.Cache.MaxSize = 50
126 integration.Cache.TTL = "PT0m"
127
128 sadis := &SadisEntries{
129 integration,
130 entries,
131 }
132
133 return sadis, nil
134}
135
136func GetOltEntry(olt *devices.OltDevice) (*SadisOltEntry, error) {
137 ip, _ := common.GetIPAddr("nni") // TODO verify which IP to report
138 solt := &SadisOltEntry{
139 ID: olt.SerialNumber,
140 HardwareIdentifier: common.Options.Olt.DeviceId,
141 IPAddress: ip,
142 NasID: olt.SerialNumber,
143 UplinkPort: 1048576, // TODO currently assumes we only have on NNI port
144 }
145 return solt, nil
146}
147
148func GetOnuEntry(olt *devices.OltDevice, onu *devices.Onu, uniId string) (*SadisOnuEntry, error) {
149 uniSuffix := "-" + uniId
150 sonu := &SadisOnuEntry{
151 ID: onu.Sn() + uniSuffix,
152 CTag: onu.CTag,
153 STag: onu.STag,
154 NasPortID: onu.Sn() + uniSuffix,
155 CircuitID: onu.Sn() + uniSuffix,
156 RemoteID: olt.SerialNumber,
157 TechnologyProfileID: 64,
158 UpstreamBandwidthProfile: "User_Bandwidth1",
159 DownstreamBandwidthProfile: "Default",
160 }
161
162 return sonu, nil
163}
164
165func getBWPEntries() *BandwidthProfileEntries {
166 a := strings.Split(common.Options.BBSim.SadisRestAddress, ":")
167 port := a[len(a)-1]
168
169 integration := SadisIntegration{}
170 integration.URL = "http://bbsim:" + port + "/bandwidthprofiles/%s"
171 integration.Cache.Enabled = true
172 integration.Cache.MaxSize = 40
173 integration.Cache.TTL = "PT1m"
174
175 bwp := &BandwidthProfileEntries{
176 Integration: integration,
177 }
178
179 return bwp
180}
181
182func (s *sadisServer) ServeBaseConfig(w http.ResponseWriter, r *http.Request) {
183 w.Header().Set("Content-Type", "application/json")
184 w.WriteHeader(http.StatusOK)
185 sadisConf := GetSadisConfig(s.olt)
186
187 sadisJSON, _ := json.Marshal(sadisConf)
188 sadisLogger.Tracef("SADIS JSON: %s", sadisJSON)
189
190 w.Write([]byte(sadisJSON))
191
192}
193
194func (s *sadisServer) ServeStaticConfig(w http.ResponseWriter, r *http.Request) {
195 w.Header().Set("Content-Type", "application/json")
196 w.WriteHeader(http.StatusOK)
197 sadisConf := GetSadisConfig(s.olt)
198
199 sadisConf.Sadis.Integration.URL = ""
200 for i := range s.olt.Pons {
201 for _, onu := range s.olt.Pons[i].Onus {
202 // FIXME currently we only support one UNI per ONU
203 sonu, _ := GetOnuEntry(s.olt, onu, "1")
204 sadisConf.Sadis.Entries = append(sadisConf.Sadis.Entries, sonu)
205 }
206 }
207
208 sadisConf.BandwidthProfile.Integration.URL = ""
209 sadisConf.BandwidthProfile.Entries = bandwidthProfiles
210
211 sadisJSON, _ := json.Marshal(sadisConf)
212 sadisLogger.Tracef("SADIS JSON: %s", sadisJSON)
213
214 w.Write([]byte(sadisJSON))
215
216}
217
218func (s *sadisServer) ServeEntry(w http.ResponseWriter, r *http.Request) {
219 w.Header().Set("Content-Type", "application/json")
220 vars := mux.Vars(r)
221
222 // check if the requested ID is for the OLT
223 if s.olt.SerialNumber == vars["ID"] {
224 sadisLogger.WithFields(log.Fields{
225 "OltSn": s.olt.SerialNumber,
226 }).Debug("Received SADIS OLT request")
227
228 sadisConf, _ := GetOltEntry(s.olt)
229
230 w.WriteHeader(http.StatusOK)
231 json.NewEncoder(w).Encode(sadisConf)
232 return
233 }
234
235 i := strings.Split(vars["ID"], "-") // split ID to get serial number and uni port
236 if len(i) != 2 {
237 w.WriteHeader(http.StatusUnprocessableEntity)
238 w.Write([]byte("{}"))
239 sadisLogger.Warnf("Received invalid SADIS subscriber request: %s", vars["ID"])
240 return
241 }
242 sn, uni := i[0], i[len(i)-1]
243
244 onu, err := s.olt.FindOnuBySn(sn)
245 if err != nil {
246 w.WriteHeader(http.StatusNotFound)
247 w.Write([]byte("{}"))
248 sadisLogger.WithFields(log.Fields{
249 "OnuSn": sn,
250 "OnuId": "NA",
251 }).Warnf("Received invalid SADIS subscriber request: %s", vars["ID"])
252 return
253 }
254
255 sadisLogger.WithFields(log.Fields{
256 "OnuId": onu.ID,
257 "OnuSn": sn,
258 "OnuPortNo": uni,
259 }).Debug("Received SADIS request")
260
261 sadisConf, err := GetOnuEntry(s.olt, onu, uni)
262
263 w.WriteHeader(http.StatusOK)
264 json.NewEncoder(w).Encode(sadisConf)
265}
266
267func (s *sadisServer) ServeBWPEntry(w http.ResponseWriter, r *http.Request) {
268 w.Header().Set("Content-Type", "application/json")
269 vars := mux.Vars(r)
270 id := vars["ID"]
271 sadisLogger.Debugf("Received request for SADIS bandwidth profile %s", id)
272
273 for _, e := range bandwidthProfiles {
274 bwpEntry := e.(*SadisBWPEntry)
275 if bwpEntry.ID == id {
276 w.WriteHeader(http.StatusOK)
277 json.NewEncoder(w).Encode(bwpEntry)
278 return
279 }
280 }
281
282 w.WriteHeader(http.StatusNotFound)
283 w.Write([]byte("{}"))
284}
285
286// StartRestServer starts REST server which returns a SADIS configuration for the currently simulated OLT
287func StartRestServer(olt *devices.OltDevice, wg *sync.WaitGroup) {
288 addr := common.Options.BBSim.SadisRestAddress
289 sadisLogger.Infof("SADIS server listening on %s", addr)
290 s := &sadisServer{
291 olt: olt,
292 }
293
294 router := mux.NewRouter().StrictSlash(true)
295 router.HandleFunc("/cfg", s.ServeBaseConfig)
296 router.HandleFunc("/static", s.ServeStaticConfig)
297 router.HandleFunc("/subscribers/{ID}", s.ServeEntry)
298 router.HandleFunc("/bandwidthprofiles/{ID}", s.ServeBWPEntry)
299
300 log.Fatal(http.ListenAndServe(addr, router))
301
302 wg.Done()
303}