blob: dc630924ecd532c19f9cc75435bb423dfc9c5997 [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
Anand S Kattib409ee02020-02-20 20:10:00 +053091type SadisOnuEntryV2 struct {
92 ID string `json:"id"`
93 NasPortID string `json:"nasPortId"`
94 CircuitID string `json:"circuitId"`
95 RemoteID string `json:"remoteId"`
96 UniTagList []SadisUniTag `json:"uniTagList"`
97}
98
99type SadisUniTag struct {
100 UniTagMatch int `json:"uniTagMatch"`
101 PonCTag int `json:"ponCTag"`
102 PonSTag int `json:"ponSTag"`
103 UsPonCTagPriority int `json:"usPonCTagPriority"`
104 DsPonCTagPriority int `json:"dsPonCTagPriority"`
105 UsPonSTagPriority int `json:"usPonSTagPriority"`
106 DsPonSTagPriority int `json:"dsPonSTagPriority"`
107 EnableMacLearning string `json:"enableMacLearning"`
108 ConfiguredDacAddress string `json:"configuredDacAddress"`
109 TechnologyProfileID int `json:"technologyProfileId"`
110 UpstreamBandwidthProfile string `json:"upstreamBandwidthProfile"`
111 DownstreamBandwidthProfile string `json:"downstreamBandwidthProfile"`
112 IsDhcpRequired string `json:"isDhcpRequired"`
113 IsIgmpRequired string `json:"isIgmpRequired"`
114 ServiceName string `json:"serviceName"`
115}
116
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100117// SADIS BandwithProfile Entry
118type SadisBWPEntry struct {
119 ID string `json:"id"`
120 AIR int `json:"air"`
121 CBS int `json:"cbs"`
122 CIR int `json:"cir"`
123 EBS int `json:"ebs"`
124 EIR int `json:"eir"`
125}
126
127// GetSadisConfig returns a full SADIS configuration struct ready to be marshalled into JSON
Anand S Kattib409ee02020-02-20 20:10:00 +0530128func GetSadisConfig(olt *devices.OltDevice, version string) *SadisConfig {
129 sadisEntries, _ := GetSadisEntries(olt, version)
130 bwpEntries := getBWPEntries(version)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100131
132 conf := &SadisConfig{}
133 conf.Sadis = *sadisEntries
134 conf.BandwidthProfile = *bwpEntries
135
136 return conf
137}
138
Anand S Kattib409ee02020-02-20 20:10:00 +0530139func GetSadisEntries(olt *devices.OltDevice, version string) (*SadisEntries, error) {
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100140 solt, _ := GetOltEntry(olt)
141
142 entries := []interface{}{}
143 entries = append(entries, solt)
144
145 a := strings.Split(common.Options.BBSim.SadisRestAddress, ":")
146 port := a[len(a)-1]
147
148 integration := SadisIntegration{}
Anand S Kattib409ee02020-02-20 20:10:00 +0530149 integration.URL = "http://bbsim:" + port + "/" + version + "/subscribers/%s"
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100150 integration.Cache.Enabled = false
151 integration.Cache.MaxSize = 50
152 integration.Cache.TTL = "PT0m"
153
154 sadis := &SadisEntries{
155 integration,
156 entries,
157 }
158
159 return sadis, nil
160}
161
162func GetOltEntry(olt *devices.OltDevice) (*SadisOltEntry, error) {
163 ip, _ := common.GetIPAddr("nni") // TODO verify which IP to report
164 solt := &SadisOltEntry{
165 ID: olt.SerialNumber,
166 HardwareIdentifier: common.Options.Olt.DeviceId,
167 IPAddress: ip,
168 NasID: olt.SerialNumber,
Anand S Kattib409ee02020-02-20 20:10:00 +0530169 UplinkPort: 1048576, // TODO currently assumes we only have one NNI port
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100170 }
171 return solt, nil
172}
173
Anand S Kattib409ee02020-02-20 20:10:00 +0530174func GetOnuEntryV1(olt *devices.OltDevice, onu *devices.Onu, uniId string) (*SadisOnuEntry, error) {
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100175 uniSuffix := "-" + uniId
176 sonu := &SadisOnuEntry{
177 ID: onu.Sn() + uniSuffix,
178 CTag: onu.CTag,
179 STag: onu.STag,
180 NasPortID: onu.Sn() + uniSuffix,
181 CircuitID: onu.Sn() + uniSuffix,
182 RemoteID: olt.SerialNumber,
183 TechnologyProfileID: 64,
184 UpstreamBandwidthProfile: "User_Bandwidth1",
185 DownstreamBandwidthProfile: "Default",
186 }
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100187 return sonu, nil
188}
189
Anand S Kattib409ee02020-02-20 20:10:00 +0530190func GetOnuEntryV2(olt *devices.OltDevice, onu *devices.Onu, uniId string) (*SadisOnuEntryV2, error) {
191 uniSuffix := "-" + uniId
192
193 sonuv2 := &SadisOnuEntryV2{
194 ID: onu.Sn() + uniSuffix,
195 NasPortID: onu.Sn() + uniSuffix,
196 CircuitID: onu.Sn() + uniSuffix,
197 RemoteID: olt.SerialNumber,
198 }
199 sonuUniTag := SadisUniTag{
200 UniTagMatch: 0,
201 PonCTag: onu.CTag,
202 PonSTag: onu.STag,
203 UsPonCTagPriority: 1,
204 DsPonCTagPriority: 1,
205 UsPonSTagPriority: 1,
206 DsPonSTagPriority: 1,
207 EnableMacLearning: "true",
208 ConfiguredDacAddress: "0.0.0.0",
209 TechnologyProfileID: 64,
210 UpstreamBandwidthProfile: "User_Bandwidth1",
211 DownstreamBandwidthProfile: "Default",
212 IsDhcpRequired: "true",
213 IsIgmpRequired: "true",
214 ServiceName: "Default",
215 }
216 sonuv2.UniTagList = append(sonuv2.UniTagList, sonuUniTag)
217 return sonuv2, nil
218}
219
220func getBWPEntries(version string) *BandwidthProfileEntries {
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100221 a := strings.Split(common.Options.BBSim.SadisRestAddress, ":")
222 port := a[len(a)-1]
223
224 integration := SadisIntegration{}
Anand S Kattib409ee02020-02-20 20:10:00 +0530225 integration.URL = "http://bbsim:" + port + "/" + version + "/bandwidthprofiles/%s"
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100226 integration.Cache.Enabled = true
227 integration.Cache.MaxSize = 40
228 integration.Cache.TTL = "PT1m"
229
230 bwp := &BandwidthProfileEntries{
231 Integration: integration,
232 }
233
234 return bwp
235}
236
237func (s *sadisServer) ServeBaseConfig(w http.ResponseWriter, r *http.Request) {
238 w.Header().Set("Content-Type", "application/json")
239 w.WriteHeader(http.StatusOK)
Anand S Kattib409ee02020-02-20 20:10:00 +0530240 vars := mux.Vars(r)
241
242 if vars["version"] != "v1" && vars["version"] != "v2" {
243 w.WriteHeader(http.StatusNotFound)
244 w.Write([]byte("{}"))
245 return
246 }
247
248 sadisConf := GetSadisConfig(s.olt, vars["version"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100249
250 sadisJSON, _ := json.Marshal(sadisConf)
251 sadisLogger.Tracef("SADIS JSON: %s", sadisJSON)
252
253 w.Write([]byte(sadisJSON))
254
255}
256
257func (s *sadisServer) ServeStaticConfig(w http.ResponseWriter, r *http.Request) {
258 w.Header().Set("Content-Type", "application/json")
259 w.WriteHeader(http.StatusOK)
Anand S Kattib409ee02020-02-20 20:10:00 +0530260 vars := mux.Vars(r)
261 sadisConf := GetSadisConfig(s.olt, vars["version"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100262
263 sadisConf.Sadis.Integration.URL = ""
264 for i := range s.olt.Pons {
265 for _, onu := range s.olt.Pons[i].Onus {
266 // FIXME currently we only support one UNI per ONU
Anand S Kattib409ee02020-02-20 20:10:00 +0530267 if vars["version"] == "v1" {
268 sonuV1, _ := GetOnuEntryV1(s.olt, onu, "1")
269 sadisConf.Sadis.Entries = append(sadisConf.Sadis.Entries, sonuV1)
270 } else if vars["version"] == "v2" {
271 sonuV2, _ := GetOnuEntryV2(s.olt, onu, "1")
272 sadisConf.Sadis.Entries = append(sadisConf.Sadis.Entries, sonuV2)
273
274 }
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100275 }
276 }
277
278 sadisConf.BandwidthProfile.Integration.URL = ""
279 sadisConf.BandwidthProfile.Entries = bandwidthProfiles
280
281 sadisJSON, _ := json.Marshal(sadisConf)
282 sadisLogger.Tracef("SADIS JSON: %s", sadisJSON)
283
284 w.Write([]byte(sadisJSON))
285
286}
287
288func (s *sadisServer) ServeEntry(w http.ResponseWriter, r *http.Request) {
289 w.Header().Set("Content-Type", "application/json")
290 vars := mux.Vars(r)
291
292 // check if the requested ID is for the OLT
293 if s.olt.SerialNumber == vars["ID"] {
294 sadisLogger.WithFields(log.Fields{
295 "OltSn": s.olt.SerialNumber,
296 }).Debug("Received SADIS OLT request")
297
298 sadisConf, _ := GetOltEntry(s.olt)
299
300 w.WriteHeader(http.StatusOK)
301 json.NewEncoder(w).Encode(sadisConf)
302 return
303 }
304
305 i := strings.Split(vars["ID"], "-") // split ID to get serial number and uni port
306 if len(i) != 2 {
307 w.WriteHeader(http.StatusUnprocessableEntity)
308 w.Write([]byte("{}"))
Anand S Kattib409ee02020-02-20 20:10:00 +0530309 sadisLogger.Warnf("Received invalid SADIS SubscriberId: %s", vars["ID"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100310 return
311 }
312 sn, uni := i[0], i[len(i)-1]
313
314 onu, err := s.olt.FindOnuBySn(sn)
315 if err != nil {
316 w.WriteHeader(http.StatusNotFound)
317 w.Write([]byte("{}"))
318 sadisLogger.WithFields(log.Fields{
319 "OnuSn": sn,
320 "OnuId": "NA",
Anand S Kattib409ee02020-02-20 20:10:00 +0530321 }).Warnf("Requested Subscriber entry not found for OnuSn: %s", vars["ID"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100322 return
323 }
324
325 sadisLogger.WithFields(log.Fields{
326 "OnuId": onu.ID,
327 "OnuSn": sn,
328 "OnuPortNo": uni,
329 }).Debug("Received SADIS request")
330
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100331 w.WriteHeader(http.StatusOK)
Anand S Kattib409ee02020-02-20 20:10:00 +0530332 if vars["version"] == "v1" {
333 sadisConf, _ := GetOnuEntryV1(s.olt, onu, uni)
334 json.NewEncoder(w).Encode(sadisConf)
335 } else if vars["version"] == "v2" {
336 sadisConf, _ := GetOnuEntryV2(s.olt, onu, uni)
337 json.NewEncoder(w).Encode(sadisConf)
338 }
339
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100340}
341
342func (s *sadisServer) ServeBWPEntry(w http.ResponseWriter, r *http.Request) {
343 w.Header().Set("Content-Type", "application/json")
344 vars := mux.Vars(r)
345 id := vars["ID"]
Anand S Kattib409ee02020-02-20 20:10:00 +0530346
347 if vars["version"] != "v1" && vars["version"] != "v2" {
348 w.WriteHeader(http.StatusNotFound)
349 w.Write([]byte("{}"))
350 return
351 }
352
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100353 sadisLogger.Debugf("Received request for SADIS bandwidth profile %s", id)
354
355 for _, e := range bandwidthProfiles {
356 bwpEntry := e.(*SadisBWPEntry)
357 if bwpEntry.ID == id {
358 w.WriteHeader(http.StatusOK)
359 json.NewEncoder(w).Encode(bwpEntry)
360 return
361 }
362 }
363
364 w.WriteHeader(http.StatusNotFound)
365 w.Write([]byte("{}"))
366}
367
368// StartRestServer starts REST server which returns a SADIS configuration for the currently simulated OLT
369func StartRestServer(olt *devices.OltDevice, wg *sync.WaitGroup) {
370 addr := common.Options.BBSim.SadisRestAddress
371 sadisLogger.Infof("SADIS server listening on %s", addr)
372 s := &sadisServer{
373 olt: olt,
374 }
375
376 router := mux.NewRouter().StrictSlash(true)
Anand S Kattib409ee02020-02-20 20:10:00 +0530377 router.HandleFunc("/{version}/cfg", s.ServeBaseConfig)
378 router.HandleFunc("/{version}/static", s.ServeStaticConfig)
379 router.HandleFunc("/{version}/subscribers/{ID}", s.ServeEntry)
380 router.HandleFunc("/{version}/bandwidthprofiles/{ID}", s.ServeBWPEntry)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100381
382 log.Fatal(http.ListenAndServe(addr, router))
383
384 wg.Done()
385}