blob: fc2b451dbc379efdfd7e9bd0796138b126219a99 [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
Matteo Scandolo51d6a312020-03-12 15:54:43 -070040var bandwidthProfiles = []*SadisBWPEntry{
41 &SadisBWPEntry{ID: "User_Bandwidth1", AIR: 100000, CBS: 10000, CIR: 30000, EBS: 1000, EIR: 100000},
42 &SadisBWPEntry{ID: "User_Bandwidth2", AIR: 100000, CBS: 5000, CIR: 100000, EBS: 5000, EIR: 100000},
43 &SadisBWPEntry{ID: "User_Bandwidth3", AIR: 100000, CBS: 5000, CIR: 1000000, EBS: 5000, EIR: 1000000},
Zdravko Bozakov958d81c2019-12-13 22:09:48 +010044 &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"`
Matteo Scandolo51d6a312020-03-12 15:54:43 -070059 Entries []*SadisBWPEntry `json:"entries,omitempty"`
Zdravko Bozakov958d81c2019-12-13 22:09:48 +010060}
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"`
Matteo Scandolof65e6872020-04-15 15:18:43 -070096 UniTagList []interface{} `json:"uniTagList"` // this can be SadisUniTagAtt, SadisUniTagDt
Anand S Kattib409ee02020-02-20 20:10:00 +053097}
98
Matteo Scandolof65e6872020-04-15 15:18:43 -070099type SadisUniTagAtt struct {
Matteo Scandolo51d6a312020-03-12 15:54:43 -0700100 PonCTag int `json:"ponCTag, omitempty"`
101 PonSTag int `json:"ponSTag, omitempty"`
102 TechnologyProfileID int `json:"technologyProfileId, omitempty"`
103 UpstreamBandwidthProfile string `json:"upstreamBandwidthProfile, omitempty"`
104 DownstreamBandwidthProfile string `json:"downstreamBandwidthProfile, omitempty"`
105 IsDhcpRequired bool `json:"isDhcpRequired, omitempty"`
106 IsIgmpRequired bool `json:"isIgmpRequired, omitempty"`
Anand S Kattib409ee02020-02-20 20:10:00 +0530107}
108
Matteo Scandolof65e6872020-04-15 15:18:43 -0700109type SadisUniTagDt struct {
110 UniTagMatch int `json:"uniTagMatch, omitempty"`
111 PonCTag int `json:"ponCTag, omitempty"`
112 PonSTag int `json:"ponSTag, omitempty"`
113 TechnologyProfileID int `json:"technologyProfileId, omitempty"`
114 UpstreamBandwidthProfile string `json:"upstreamBandwidthProfile, omitempty"`
115 DownstreamBandwidthProfile string `json:"downstreamBandwidthProfile, omitempty"`
116}
117
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100118// SADIS BandwithProfile Entry
119type SadisBWPEntry struct {
120 ID string `json:"id"`
121 AIR int `json:"air"`
122 CBS int `json:"cbs"`
123 CIR int `json:"cir"`
124 EBS int `json:"ebs"`
125 EIR int `json:"eir"`
126}
127
128// GetSadisConfig returns a full SADIS configuration struct ready to be marshalled into JSON
Anand S Kattib409ee02020-02-20 20:10:00 +0530129func GetSadisConfig(olt *devices.OltDevice, version string) *SadisConfig {
130 sadisEntries, _ := GetSadisEntries(olt, version)
131 bwpEntries := getBWPEntries(version)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100132
133 conf := &SadisConfig{}
134 conf.Sadis = *sadisEntries
135 conf.BandwidthProfile = *bwpEntries
136
137 return conf
138}
139
Anand S Kattib409ee02020-02-20 20:10:00 +0530140func GetSadisEntries(olt *devices.OltDevice, version string) (*SadisEntries, error) {
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100141 solt, _ := GetOltEntry(olt)
142
143 entries := []interface{}{}
144 entries = append(entries, solt)
145
146 a := strings.Split(common.Options.BBSim.SadisRestAddress, ":")
147 port := a[len(a)-1]
148
149 integration := SadisIntegration{}
Anand S Kattib409ee02020-02-20 20:10:00 +0530150 integration.URL = "http://bbsim:" + port + "/" + version + "/subscribers/%s"
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100151 integration.Cache.Enabled = false
152 integration.Cache.MaxSize = 50
153 integration.Cache.TTL = "PT0m"
154
155 sadis := &SadisEntries{
156 integration,
157 entries,
158 }
159
160 return sadis, nil
161}
162
163func GetOltEntry(olt *devices.OltDevice) (*SadisOltEntry, error) {
164 ip, _ := common.GetIPAddr("nni") // TODO verify which IP to report
165 solt := &SadisOltEntry{
166 ID: olt.SerialNumber,
167 HardwareIdentifier: common.Options.Olt.DeviceId,
168 IPAddress: ip,
169 NasID: olt.SerialNumber,
Anand S Kattib409ee02020-02-20 20:10:00 +0530170 UplinkPort: 1048576, // TODO currently assumes we only have one NNI port
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100171 }
172 return solt, nil
173}
174
Anand S Kattib409ee02020-02-20 20:10:00 +0530175func GetOnuEntryV1(olt *devices.OltDevice, onu *devices.Onu, uniId string) (*SadisOnuEntry, error) {
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100176 uniSuffix := "-" + uniId
177 sonu := &SadisOnuEntry{
178 ID: onu.Sn() + uniSuffix,
179 CTag: onu.CTag,
180 STag: onu.STag,
181 NasPortID: onu.Sn() + uniSuffix,
182 CircuitID: onu.Sn() + uniSuffix,
183 RemoteID: olt.SerialNumber,
184 TechnologyProfileID: 64,
185 UpstreamBandwidthProfile: "User_Bandwidth1",
186 DownstreamBandwidthProfile: "Default",
187 }
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100188 return sonu, nil
189}
190
Anand S Kattib409ee02020-02-20 20:10:00 +0530191func GetOnuEntryV2(olt *devices.OltDevice, onu *devices.Onu, uniId string) (*SadisOnuEntryV2, error) {
192 uniSuffix := "-" + uniId
193
194 sonuv2 := &SadisOnuEntryV2{
195 ID: onu.Sn() + uniSuffix,
196 NasPortID: onu.Sn() + uniSuffix,
197 CircuitID: onu.Sn() + uniSuffix,
Matteo Scandolo51d6a312020-03-12 15:54:43 -0700198 RemoteID: onu.Sn() + uniSuffix,
Anand S Kattib409ee02020-02-20 20:10:00 +0530199 }
Matteo Scandolo51d6a312020-03-12 15:54:43 -0700200
Matteo Scandolof65e6872020-04-15 15:18:43 -0700201 // base structure common to all use cases
202 var sonuUniTag interface{}
203
204 // set workflow specific params
205 switch common.Options.BBSim.SadisFormat {
206 case common.SadisFormatAtt:
207 sonuUniTag = SadisUniTagAtt{
208 PonCTag: onu.CTag,
209 PonSTag: onu.STag,
210 TechnologyProfileID: 64,
211 // NOTE do we want to select a random bandwidth profile?
212 // if so use bandwidthProfiles[rand.Intn(len(bandwidthProfiles))].ID
213 UpstreamBandwidthProfile: "Default",
214 DownstreamBandwidthProfile: "User_Bandwidth1",
215 IsDhcpRequired: true,
216 IsIgmpRequired: true,
217 }
218 case common.SadisFormatDt:
219 sonuUniTag = SadisUniTagDt{
220 PonCTag: 4096,
221 PonSTag: onu.STag,
222 TechnologyProfileID: 64,
223 // NOTE do we want to select a random bandwidth profile?
224 // if so use bandwidthProfiles[rand.Intn(len(bandwidthProfiles))].ID
225 UpstreamBandwidthProfile: "Default",
226 DownstreamBandwidthProfile: "User_Bandwidth1",
227 UniTagMatch: 4096,
228 }
Anand S Kattib409ee02020-02-20 20:10:00 +0530229 }
Matteo Scandolo51d6a312020-03-12 15:54:43 -0700230
Anand S Kattib409ee02020-02-20 20:10:00 +0530231 sonuv2.UniTagList = append(sonuv2.UniTagList, sonuUniTag)
232 return sonuv2, nil
233}
234
235func getBWPEntries(version string) *BandwidthProfileEntries {
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100236 a := strings.Split(common.Options.BBSim.SadisRestAddress, ":")
237 port := a[len(a)-1]
238
239 integration := SadisIntegration{}
Anand S Kattib409ee02020-02-20 20:10:00 +0530240 integration.URL = "http://bbsim:" + port + "/" + version + "/bandwidthprofiles/%s"
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100241 integration.Cache.Enabled = true
242 integration.Cache.MaxSize = 40
243 integration.Cache.TTL = "PT1m"
244
245 bwp := &BandwidthProfileEntries{
246 Integration: integration,
247 }
248
249 return bwp
250}
251
252func (s *sadisServer) ServeBaseConfig(w http.ResponseWriter, r *http.Request) {
253 w.Header().Set("Content-Type", "application/json")
254 w.WriteHeader(http.StatusOK)
Anand S Kattib409ee02020-02-20 20:10:00 +0530255 vars := mux.Vars(r)
256
257 if vars["version"] != "v1" && vars["version"] != "v2" {
258 w.WriteHeader(http.StatusNotFound)
259 w.Write([]byte("{}"))
260 return
261 }
262
263 sadisConf := GetSadisConfig(s.olt, vars["version"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100264
265 sadisJSON, _ := json.Marshal(sadisConf)
266 sadisLogger.Tracef("SADIS JSON: %s", sadisJSON)
267
268 w.Write([]byte(sadisJSON))
269
270}
271
272func (s *sadisServer) ServeStaticConfig(w http.ResponseWriter, r *http.Request) {
273 w.Header().Set("Content-Type", "application/json")
274 w.WriteHeader(http.StatusOK)
Anand S Kattib409ee02020-02-20 20:10:00 +0530275 vars := mux.Vars(r)
276 sadisConf := GetSadisConfig(s.olt, vars["version"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100277
278 sadisConf.Sadis.Integration.URL = ""
279 for i := range s.olt.Pons {
280 for _, onu := range s.olt.Pons[i].Onus {
281 // FIXME currently we only support one UNI per ONU
Anand S Kattib409ee02020-02-20 20:10:00 +0530282 if vars["version"] == "v1" {
283 sonuV1, _ := GetOnuEntryV1(s.olt, onu, "1")
284 sadisConf.Sadis.Entries = append(sadisConf.Sadis.Entries, sonuV1)
285 } else if vars["version"] == "v2" {
286 sonuV2, _ := GetOnuEntryV2(s.olt, onu, "1")
287 sadisConf.Sadis.Entries = append(sadisConf.Sadis.Entries, sonuV2)
288
289 }
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100290 }
291 }
292
293 sadisConf.BandwidthProfile.Integration.URL = ""
294 sadisConf.BandwidthProfile.Entries = bandwidthProfiles
295
296 sadisJSON, _ := json.Marshal(sadisConf)
297 sadisLogger.Tracef("SADIS JSON: %s", sadisJSON)
298
299 w.Write([]byte(sadisJSON))
300
301}
302
303func (s *sadisServer) ServeEntry(w http.ResponseWriter, r *http.Request) {
304 w.Header().Set("Content-Type", "application/json")
305 vars := mux.Vars(r)
306
307 // check if the requested ID is for the OLT
308 if s.olt.SerialNumber == vars["ID"] {
309 sadisLogger.WithFields(log.Fields{
310 "OltSn": s.olt.SerialNumber,
311 }).Debug("Received SADIS OLT request")
312
313 sadisConf, _ := GetOltEntry(s.olt)
314
315 w.WriteHeader(http.StatusOK)
316 json.NewEncoder(w).Encode(sadisConf)
317 return
318 }
319
320 i := strings.Split(vars["ID"], "-") // split ID to get serial number and uni port
321 if len(i) != 2 {
322 w.WriteHeader(http.StatusUnprocessableEntity)
323 w.Write([]byte("{}"))
Anand S Kattib409ee02020-02-20 20:10:00 +0530324 sadisLogger.Warnf("Received invalid SADIS SubscriberId: %s", vars["ID"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100325 return
326 }
327 sn, uni := i[0], i[len(i)-1]
328
329 onu, err := s.olt.FindOnuBySn(sn)
330 if err != nil {
331 w.WriteHeader(http.StatusNotFound)
332 w.Write([]byte("{}"))
333 sadisLogger.WithFields(log.Fields{
334 "OnuSn": sn,
335 "OnuId": "NA",
Anand S Kattib409ee02020-02-20 20:10:00 +0530336 }).Warnf("Requested Subscriber entry not found for OnuSn: %s", vars["ID"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100337 return
338 }
339
340 sadisLogger.WithFields(log.Fields{
341 "OnuId": onu.ID,
342 "OnuSn": sn,
343 "OnuPortNo": uni,
344 }).Debug("Received SADIS request")
345
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100346 w.WriteHeader(http.StatusOK)
Anand S Kattib409ee02020-02-20 20:10:00 +0530347 if vars["version"] == "v1" {
348 sadisConf, _ := GetOnuEntryV1(s.olt, onu, uni)
349 json.NewEncoder(w).Encode(sadisConf)
350 } else if vars["version"] == "v2" {
351 sadisConf, _ := GetOnuEntryV2(s.olt, onu, uni)
352 json.NewEncoder(w).Encode(sadisConf)
353 }
354
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100355}
356
357func (s *sadisServer) ServeBWPEntry(w http.ResponseWriter, r *http.Request) {
358 w.Header().Set("Content-Type", "application/json")
359 vars := mux.Vars(r)
360 id := vars["ID"]
Anand S Kattib409ee02020-02-20 20:10:00 +0530361
362 if vars["version"] != "v1" && vars["version"] != "v2" {
363 w.WriteHeader(http.StatusNotFound)
364 w.Write([]byte("{}"))
365 return
366 }
367
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100368 sadisLogger.Debugf("Received request for SADIS bandwidth profile %s", id)
369
Matteo Scandolo51d6a312020-03-12 15:54:43 -0700370 for _, bwpEntry := range bandwidthProfiles {
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100371 if bwpEntry.ID == id {
372 w.WriteHeader(http.StatusOK)
373 json.NewEncoder(w).Encode(bwpEntry)
374 return
375 }
376 }
377
378 w.WriteHeader(http.StatusNotFound)
379 w.Write([]byte("{}"))
380}
381
382// StartRestServer starts REST server which returns a SADIS configuration for the currently simulated OLT
383func StartRestServer(olt *devices.OltDevice, wg *sync.WaitGroup) {
384 addr := common.Options.BBSim.SadisRestAddress
385 sadisLogger.Infof("SADIS server listening on %s", addr)
386 s := &sadisServer{
387 olt: olt,
388 }
389
390 router := mux.NewRouter().StrictSlash(true)
Anand S Kattib409ee02020-02-20 20:10:00 +0530391 router.HandleFunc("/{version}/cfg", s.ServeBaseConfig)
392 router.HandleFunc("/{version}/static", s.ServeStaticConfig)
393 router.HandleFunc("/{version}/subscribers/{ID}", s.ServeEntry)
394 router.HandleFunc("/{version}/bandwidthprofiles/{ID}", s.ServeBWPEntry)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100395
396 log.Fatal(http.ListenAndServe(addr, router))
397
398 wg.Done()
399}