blob: 34bf600911899b337b9f76a444bb1e34e6e6c212 [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{
Shrey Baid688b4242020-07-10 20:40:10 +053041 {ID: "User_Bandwidth1", AIR: 100000, CBS: 10000, CIR: 30000, EBS: 1000, EIR: 100000},
42 {ID: "User_Bandwidth2", AIR: 100000, CBS: 5000, CIR: 100000, EBS: 5000, EIR: 100000},
43 {ID: "User_Bandwidth3", AIR: 100000, CBS: 5000, CIR: 1000000, EBS: 5000, EIR: 1000000},
44 {ID: "Default", AIR: 100000, CBS: 30, CIR: 600, EBS: 30, EIR: 400},
Zdravko Bozakov958d81c2019-12-13 22:09:48 +010045}
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
Anand S Kattib409ee02020-02-20 20:10:00 +053079type SadisOnuEntryV2 struct {
80 ID string `json:"id"`
81 NasPortID string `json:"nasPortId"`
82 CircuitID string `json:"circuitId"`
83 RemoteID string `json:"remoteId"`
Matteo Scandolo4a036262020-08-17 15:56:13 -070084 UniTagList []SadisUniTag `json:"uniTagList"` // this can be SadisUniTagAtt, SadisUniTagDt
Anand S Kattib409ee02020-02-20 20:10:00 +053085}
86
Matteo Scandolo4a036262020-08-17 15:56:13 -070087type SadisUniTag struct {
88 UniTagMatch int `json:"uniTagMatch,omitempty"`
Shrey Baid688b4242020-07-10 20:40:10 +053089 PonCTag int `json:"ponCTag,omitempty"`
90 PonSTag int `json:"ponSTag,omitempty"`
91 TechnologyProfileID int `json:"technologyProfileId,omitempty"`
92 UpstreamBandwidthProfile string `json:"upstreamBandwidthProfile,omitempty"`
93 DownstreamBandwidthProfile string `json:"downstreamBandwidthProfile,omitempty"`
94 IsDhcpRequired bool `json:"isDhcpRequired,omitempty"`
95 IsIgmpRequired bool `json:"isIgmpRequired,omitempty"`
Matteo Scandolo4a036262020-08-17 15:56:13 -070096 ConfiguredMacAddress string `json:"configuredMacAddress,omitempty"`
Matteo Scandolo8d281372020-09-03 16:23:37 -070097 UsPonCTagPriority uint8 `json:"usPonCTagPriority,omitempty"`
98 UsPonSTagPriority uint8 `json:"usPonSTagPriority,omitempty"`
99 DsPonCTagPriority uint8 `json:"dsPonCTagPriority,omitempty"`
100 DsPonSTagPriority uint8 `json:"dsPonSTagPriority,omitempty"`
Matteo Scandolo4a036262020-08-17 15:56:13 -0700101 ServiceName string `json:"serviceName,omitempty"`
Matteo Scandolof65e6872020-04-15 15:18:43 -0700102}
103
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100104// SADIS BandwithProfile Entry
105type SadisBWPEntry struct {
106 ID string `json:"id"`
107 AIR int `json:"air"`
108 CBS int `json:"cbs"`
109 CIR int `json:"cir"`
110 EBS int `json:"ebs"`
111 EIR int `json:"eir"`
112}
113
114// GetSadisConfig returns a full SADIS configuration struct ready to be marshalled into JSON
Anand S Kattib409ee02020-02-20 20:10:00 +0530115func GetSadisConfig(olt *devices.OltDevice, version string) *SadisConfig {
116 sadisEntries, _ := GetSadisEntries(olt, version)
117 bwpEntries := getBWPEntries(version)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100118
119 conf := &SadisConfig{}
120 conf.Sadis = *sadisEntries
121 conf.BandwidthProfile = *bwpEntries
122
123 return conf
124}
125
Anand S Kattib409ee02020-02-20 20:10:00 +0530126func GetSadisEntries(olt *devices.OltDevice, version string) (*SadisEntries, error) {
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100127 solt, _ := GetOltEntry(olt)
128
129 entries := []interface{}{}
130 entries = append(entries, solt)
131
Matteo Scandolo4a036262020-08-17 15:56:13 -0700132 a := strings.Split(common.Config.BBSim.SadisRestAddress, ":")
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100133 port := a[len(a)-1]
134
135 integration := SadisIntegration{}
Anand S Kattib409ee02020-02-20 20:10:00 +0530136 integration.URL = "http://bbsim:" + port + "/" + version + "/subscribers/%s"
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100137 integration.Cache.Enabled = false
138 integration.Cache.MaxSize = 50
139 integration.Cache.TTL = "PT0m"
140
141 sadis := &SadisEntries{
142 integration,
143 entries,
144 }
145
146 return sadis, nil
147}
148
149func GetOltEntry(olt *devices.OltDevice) (*SadisOltEntry, error) {
150 ip, _ := common.GetIPAddr("nni") // TODO verify which IP to report
151 solt := &SadisOltEntry{
152 ID: olt.SerialNumber,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700153 HardwareIdentifier: common.Config.Olt.DeviceId,
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100154 IPAddress: ip,
155 NasID: olt.SerialNumber,
Anand S Kattib409ee02020-02-20 20:10:00 +0530156 UplinkPort: 1048576, // TODO currently assumes we only have one NNI port
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100157 }
158 return solt, nil
159}
160
Anand S Kattib409ee02020-02-20 20:10:00 +0530161func GetOnuEntryV2(olt *devices.OltDevice, onu *devices.Onu, uniId string) (*SadisOnuEntryV2, error) {
162 uniSuffix := "-" + uniId
163
164 sonuv2 := &SadisOnuEntryV2{
165 ID: onu.Sn() + uniSuffix,
166 NasPortID: onu.Sn() + uniSuffix,
167 CircuitID: onu.Sn() + uniSuffix,
Matteo Scandolo51d6a312020-03-12 15:54:43 -0700168 RemoteID: onu.Sn() + uniSuffix,
Anand S Kattib409ee02020-02-20 20:10:00 +0530169 }
Matteo Scandolo51d6a312020-03-12 15:54:43 -0700170
Matteo Scandolo4a036262020-08-17 15:56:13 -0700171 // createUniTagList
172 for _, s := range onu.Services {
Matteo Scandolof65e6872020-04-15 15:18:43 -0700173
Matteo Scandolo4a036262020-08-17 15:56:13 -0700174 service := s.(*devices.Service)
175
176 tag := SadisUniTag{
177 ServiceName: service.Name,
178 IsIgmpRequired: service.NeedsIgmp,
179 IsDhcpRequired: service.NeedsDhcp,
180 TechnologyProfileID: service.TechnologyProfileID,
181 UpstreamBandwidthProfile: "User_Bandwidth1",
182 DownstreamBandwidthProfile: "User_Bandwidth2",
183 PonCTag: service.CTag,
184 PonSTag: service.STag,
Matteo Scandolof65e6872020-04-15 15:18:43 -0700185 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700186
187 if service.UniTagMatch != 0 {
188 tag.UniTagMatch = service.UniTagMatch
Matteo Scandolof65e6872020-04-15 15:18:43 -0700189 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700190
191 if service.ConfigureMacAddress {
192 tag.ConfiguredMacAddress = service.HwAddress.String()
193 }
194
195 if service.UsPonCTagPriority != 0 {
196 tag.UsPonCTagPriority = service.UsPonCTagPriority
197 }
198
199 if service.UsPonSTagPriority != 0 {
200 tag.UsPonSTagPriority = service.UsPonSTagPriority
201 }
202
203 if service.DsPonCTagPriority != 0 {
204 tag.DsPonCTagPriority = service.DsPonCTagPriority
205 }
206
207 if service.DsPonSTagPriority != 0 {
208 tag.DsPonSTagPriority = service.DsPonSTagPriority
209 }
210
211 sonuv2.UniTagList = append(sonuv2.UniTagList, tag)
Anand S Kattib409ee02020-02-20 20:10:00 +0530212 }
Matteo Scandolo51d6a312020-03-12 15:54:43 -0700213
Anand S Kattib409ee02020-02-20 20:10:00 +0530214 return sonuv2, nil
215}
216
217func getBWPEntries(version string) *BandwidthProfileEntries {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700218 a := strings.Split(common.Config.BBSim.SadisRestAddress, ":")
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100219 port := a[len(a)-1]
220
221 integration := SadisIntegration{}
Anand S Kattib409ee02020-02-20 20:10:00 +0530222 integration.URL = "http://bbsim:" + port + "/" + version + "/bandwidthprofiles/%s"
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100223 integration.Cache.Enabled = true
224 integration.Cache.MaxSize = 40
225 integration.Cache.TTL = "PT1m"
226
227 bwp := &BandwidthProfileEntries{
228 Integration: integration,
229 }
230
231 return bwp
232}
233
234func (s *sadisServer) ServeBaseConfig(w http.ResponseWriter, r *http.Request) {
235 w.Header().Set("Content-Type", "application/json")
236 w.WriteHeader(http.StatusOK)
Anand S Kattib409ee02020-02-20 20:10:00 +0530237 vars := mux.Vars(r)
238
239 if vars["version"] != "v1" && vars["version"] != "v2" {
240 w.WriteHeader(http.StatusNotFound)
Shrey Baid688b4242020-07-10 20:40:10 +0530241 _, _ = w.Write([]byte("{}"))
Anand S Kattib409ee02020-02-20 20:10:00 +0530242 return
243 }
244
245 sadisConf := GetSadisConfig(s.olt, vars["version"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100246
247 sadisJSON, _ := json.Marshal(sadisConf)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100248
Shrey Baid688b4242020-07-10 20:40:10 +0530249 _, _ = w.Write([]byte(sadisJSON))
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100250
251}
252
253func (s *sadisServer) ServeStaticConfig(w http.ResponseWriter, r *http.Request) {
254 w.Header().Set("Content-Type", "application/json")
255 w.WriteHeader(http.StatusOK)
Anand S Kattib409ee02020-02-20 20:10:00 +0530256 vars := mux.Vars(r)
257 sadisConf := GetSadisConfig(s.olt, vars["version"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100258
259 sadisConf.Sadis.Integration.URL = ""
260 for i := range s.olt.Pons {
261 for _, onu := range s.olt.Pons[i].Onus {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700262 if vars["version"] == "v2" {
Anand S Kattib409ee02020-02-20 20:10:00 +0530263 sonuV2, _ := GetOnuEntryV2(s.olt, onu, "1")
264 sadisConf.Sadis.Entries = append(sadisConf.Sadis.Entries, sonuV2)
Anand S Kattib409ee02020-02-20 20:10:00 +0530265 }
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100266 }
267 }
268
269 sadisConf.BandwidthProfile.Integration.URL = ""
270 sadisConf.BandwidthProfile.Entries = bandwidthProfiles
271
272 sadisJSON, _ := json.Marshal(sadisConf)
273 sadisLogger.Tracef("SADIS JSON: %s", sadisJSON)
274
Shrey Baid688b4242020-07-10 20:40:10 +0530275 _, _ = w.Write([]byte(sadisJSON))
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100276
277}
278
279func (s *sadisServer) ServeEntry(w http.ResponseWriter, r *http.Request) {
280 w.Header().Set("Content-Type", "application/json")
281 vars := mux.Vars(r)
282
283 // check if the requested ID is for the OLT
284 if s.olt.SerialNumber == vars["ID"] {
285 sadisLogger.WithFields(log.Fields{
286 "OltSn": s.olt.SerialNumber,
287 }).Debug("Received SADIS OLT request")
288
289 sadisConf, _ := GetOltEntry(s.olt)
290
291 w.WriteHeader(http.StatusOK)
Shrey Baid688b4242020-07-10 20:40:10 +0530292 _ = json.NewEncoder(w).Encode(sadisConf)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100293 return
294 }
295
296 i := strings.Split(vars["ID"], "-") // split ID to get serial number and uni port
297 if len(i) != 2 {
298 w.WriteHeader(http.StatusUnprocessableEntity)
Shrey Baid688b4242020-07-10 20:40:10 +0530299 _, _ = w.Write([]byte("{}"))
Anand S Kattib409ee02020-02-20 20:10:00 +0530300 sadisLogger.Warnf("Received invalid SADIS SubscriberId: %s", vars["ID"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100301 return
302 }
303 sn, uni := i[0], i[len(i)-1]
304
305 onu, err := s.olt.FindOnuBySn(sn)
306 if err != nil {
307 w.WriteHeader(http.StatusNotFound)
Shrey Baid688b4242020-07-10 20:40:10 +0530308 _, _ = w.Write([]byte("{}"))
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100309 sadisLogger.WithFields(log.Fields{
310 "OnuSn": sn,
311 "OnuId": "NA",
Anand S Kattib409ee02020-02-20 20:10:00 +0530312 }).Warnf("Requested Subscriber entry not found for OnuSn: %s", vars["ID"])
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100313 return
314 }
315
316 sadisLogger.WithFields(log.Fields{
317 "OnuId": onu.ID,
318 "OnuSn": sn,
319 "OnuPortNo": uni,
320 }).Debug("Received SADIS request")
321
Anand S Kattib409ee02020-02-20 20:10:00 +0530322 if vars["version"] == "v1" {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700323 // TODO format error
324 w.WriteHeader(http.StatusBadRequest)
325 _ = json.NewEncoder(w).Encode("Sadis v1 is not supported anymore, please go back to an earlier BBSim version")
Anand S Kattib409ee02020-02-20 20:10:00 +0530326 } else if vars["version"] == "v2" {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700327 w.WriteHeader(http.StatusOK)
Anand S Kattib409ee02020-02-20 20:10:00 +0530328 sadisConf, _ := GetOnuEntryV2(s.olt, onu, uni)
Shrey Baid688b4242020-07-10 20:40:10 +0530329 _ = json.NewEncoder(w).Encode(sadisConf)
Anand S Kattib409ee02020-02-20 20:10:00 +0530330 }
331
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100332}
333
334func (s *sadisServer) ServeBWPEntry(w http.ResponseWriter, r *http.Request) {
335 w.Header().Set("Content-Type", "application/json")
336 vars := mux.Vars(r)
337 id := vars["ID"]
Anand S Kattib409ee02020-02-20 20:10:00 +0530338
339 if vars["version"] != "v1" && vars["version"] != "v2" {
340 w.WriteHeader(http.StatusNotFound)
Shrey Baid688b4242020-07-10 20:40:10 +0530341 _, _ = w.Write([]byte("{}"))
Anand S Kattib409ee02020-02-20 20:10:00 +0530342 return
343 }
344
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100345 sadisLogger.Debugf("Received request for SADIS bandwidth profile %s", id)
346
Matteo Scandolo51d6a312020-03-12 15:54:43 -0700347 for _, bwpEntry := range bandwidthProfiles {
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100348 if bwpEntry.ID == id {
349 w.WriteHeader(http.StatusOK)
Shrey Baid688b4242020-07-10 20:40:10 +0530350 _ = json.NewEncoder(w).Encode(bwpEntry)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100351 return
352 }
353 }
354
355 w.WriteHeader(http.StatusNotFound)
Shrey Baid688b4242020-07-10 20:40:10 +0530356 _, _ = w.Write([]byte("{}"))
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100357}
358
359// StartRestServer starts REST server which returns a SADIS configuration for the currently simulated OLT
360func StartRestServer(olt *devices.OltDevice, wg *sync.WaitGroup) {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700361 addr := common.Config.BBSim.SadisRestAddress
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100362 sadisLogger.Infof("SADIS server listening on %s", addr)
363 s := &sadisServer{
364 olt: olt,
365 }
366
367 router := mux.NewRouter().StrictSlash(true)
Anand S Kattib409ee02020-02-20 20:10:00 +0530368 router.HandleFunc("/{version}/cfg", s.ServeBaseConfig)
369 router.HandleFunc("/{version}/static", s.ServeStaticConfig)
370 router.HandleFunc("/{version}/subscribers/{ID}", s.ServeEntry)
371 router.HandleFunc("/{version}/bandwidthprofiles/{ID}", s.ServeBWPEntry)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100372
373 log.Fatal(http.ListenAndServe(addr, router))
374
375 wg.Done()
376}