blob: 9978d9ed82b3b60f238674261d7cf5c7549f0ee4 [file] [log] [blame]
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001/*
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 common
18
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +010019import (
20 "flag"
21 "fmt"
22 "io/ioutil"
23 "net"
Matteo Scandolof65e6872020-04-15 15:18:43 -070024 "strings"
Shrey Baid64cda472020-04-24 18:58:18 +053025
Matteo Scandolo4a036262020-08-17 15:56:13 -070026 "github.com/imdario/mergo"
Shrey Baid64cda472020-04-24 18:58:18 +053027 log "github.com/sirupsen/logrus"
Matteo Scandolo4a036262020-08-17 15:56:13 -070028 "gopkg.in/yaml.v2"
Matteo Scandolof65e6872020-04-15 15:18:43 -070029)
Matteo Scandolo40e067f2019-10-16 16:59:41 -070030
Matteo Scandolof65e6872020-04-15 15:18:43 -070031var tagAllocationValues = []string{
32 "unknown",
33 "shared",
34 "unique",
35}
36
37type TagAllocation int
38
39func (t TagAllocation) String() string {
40 return tagAllocationValues[t]
41}
42
43func tagAllocationFromString(s string) (TagAllocation, error) {
44 for i, v := range tagAllocationValues {
Matteo Scandolo4a036262020-08-17 15:56:13 -070045 if v == strings.TrimSpace(s) {
Matteo Scandolof65e6872020-04-15 15:18:43 -070046 return TagAllocation(i), nil
47 }
48 }
49 log.WithFields(log.Fields{
50 "ValidValues": strings.Join(tagAllocationValues[1:], ", "),
51 }).Errorf("%s-is-not-a-valid-tag-allocation", s)
Shrey Baid688b4242020-07-10 20:40:10 +053052 return TagAllocation(0), fmt.Errorf("%s-is-not-a-valid-tag-allocation", s)
Matteo Scandolof65e6872020-04-15 15:18:43 -070053}
54
55const (
56 _ TagAllocation = iota
57 TagAllocationShared
58 TagAllocationUnique
59)
60
Matteo Scandolo40e067f2019-10-16 16:59:41 -070061type BBRCliOptions struct {
Matteo Scandolo4a036262020-08-17 15:56:13 -070062 *GlobalConfig
Matteo Scandolo40e067f2019-10-16 16:59:41 -070063 BBSimIp string
64 BBSimPort string
65 BBSimApiPort string
Matteo Scandolof5c537e2019-10-28 16:45:57 -070066 LogFile string
Matteo Scandolo40e067f2019-10-16 16:59:41 -070067}
68
Matteo Scandolo4a036262020-08-17 15:56:13 -070069type GlobalConfig struct {
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +010070 BBSim BBSimConfig
71 Olt OltConfig
72 BBR BBRConfig
73}
Matteo Scandolo40e067f2019-10-16 16:59:41 -070074
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +010075type OltConfig struct {
76 Model string `yaml:"model"`
77 Vendor string `yaml:"vendor"`
78 HardwareVersion string `yaml:"hardware_version"`
79 FirmwareVersion string `yaml:"firmware_version"`
80 DeviceId string `yaml:"device_id"`
81 DeviceSerialNumber string `yaml:"device_serial_number"`
82 PonPorts uint32 `yaml:"pon_ports"`
83 NniPorts uint32 `yaml:"nni_ports"`
84 OnusPonPort uint32 `yaml:"onus_per_port"`
85 Technology string `yaml:"technology"`
86 ID int `yaml:"id"`
87 OltRebootDelay int `yaml:"reboot_delay"`
Shrey Baid688b4242020-07-10 20:40:10 +053088 PortStatsInterval int `yaml:"port_stats_interval"`
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +010089}
Matteo Scandolo40e067f2019-10-16 16:59:41 -070090
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +010091type BBSimConfig struct {
Matteo Scandolo4a036262020-08-17 15:56:13 -070092 ConfigFile string
93 ServiceConfigFile string
94 DhcpRetry bool `yaml:"dhcp_retry"`
95 AuthRetry bool `yaml:"auth_retry"`
96 LogLevel string `yaml:"log_level"`
97 LogCaller bool `yaml:"log_caller"`
98 Delay int `yaml:"delay"`
99 CpuProfile *string `yaml:"cpu_profile"`
100 OpenOltAddress string `yaml:"openolt_address"`
101 ApiAddress string `yaml:"api_address"`
102 RestApiAddress string `yaml:"rest_api_address"`
103 LegacyApiAddress string `yaml:"legacy_api_address"`
104 LegacyRestApiAddress string `yaml:"legacy_rest_api_address"`
105 SadisRestAddress string `yaml:"sadis_rest_address"`
106 SadisServer bool `yaml:"sadis_server"`
107 KafkaAddress string `yaml:"kafka_address"`
108 Events bool `yaml:"enable_events"`
109 ControlledActivation string `yaml:"controlled_activation"`
110 EnablePerf bool `yaml:"enable_perf"`
111 KafkaEventTopic string `yaml:"kafka_event_topic"`
amit.ghosh258d14c2020-10-02 15:13:38 +0200112 DmiServerAddress string `yaml:"dmi_server_address"`
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100113}
Matteo Scandoloc1147092019-10-29 09:38:33 -0700114
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100115type BBRConfig struct {
116 Log string `yaml:"log"`
117 LogLevel string `yaml:"log_level"`
118 LogCaller bool `yaml:"log_caller"`
119}
120
Matteo Scandolo4a036262020-08-17 15:56:13 -0700121type ServiceYaml struct {
122 Name string
123 CTag int `yaml:"c_tag"`
124 STag int `yaml:"s_tag"`
125 NeedsEapol bool `yaml:"needs_eapol"`
126 NeedsDchp bool `yaml:"needs_dhcp"`
127 NeedsIgmp bool `yaml:"needs_igmp"`
128 CTagAllocation string `yaml:"c_tag_allocation"`
129 STagAllocation string `yaml:"s_tag_allocation"`
130 TechnologyProfileID int `yaml:"tp_id"`
131 UniTagMatch int `yaml:"uni_tag_match"`
132 ConfigureMacAddress bool `yaml:"configure_mac_address"`
Matteo Scandolo8d281372020-09-03 16:23:37 -0700133 UsPonCTagPriority uint8 `yaml:"us_pon_c_tag_priority"`
134 UsPonSTagPriority uint8 `yaml:"us_pon_s_tag_priority"`
135 DsPonCTagPriority uint8 `yaml:"ds_pon_c_tag_priority"`
136 DsPonSTagPriority uint8 `yaml:"ds_pon_s_tag_priority"`
Matteo Scandolo4a036262020-08-17 15:56:13 -0700137}
138type YamlServiceConfig struct {
139 Workflow string
140 Services []ServiceYaml `yaml:"services,flow"`
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100141}
142
Matteo Scandolo4a036262020-08-17 15:56:13 -0700143func (cfg *YamlServiceConfig) String() string {
144 str := fmt.Sprintf("[workflow: %s, Services: ", cfg.Workflow)
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100145
Matteo Scandolo4a036262020-08-17 15:56:13 -0700146 for _, s := range cfg.Services {
147 str = fmt.Sprintf("%s[", str)
148 str = fmt.Sprintf("%sname=%s, c_tag=%d, s_tag=%d, ",
149 str, s.Name, s.CTag, s.STag)
150 str = fmt.Sprintf("%sc_tag_allocation=%s, s_tag_allocation=%s, ",
151 str, s.CTagAllocation, s.STagAllocation)
152 str = fmt.Sprintf("%sneeds_eapol=%t, needs_dhcp=%t, needs_igmp=%t",
153 str, s.NeedsEapol, s.NeedsDchp, s.NeedsIgmp)
154 str = fmt.Sprintf("%stp_id=%d, uni_tag_match=%d",
155 str, s.TechnologyProfileID, s.UniTagMatch)
156 str = fmt.Sprintf("%s]", str)
157 }
158 str = fmt.Sprintf("%s]", str)
159 return str
160}
161
162var (
163 Config *GlobalConfig
164 Services []ServiceYaml
165)
166
167// Load the BBSim configuration. This is a combination of CLI parameters and YAML files
168// We proceed in this order:
169// - Read CLI parameters
170// - Using those we read the yaml files (config and services)
171// - we merge the configuration (CLI has priority over yaml files)
172func LoadConfig() {
173
174 Config = getDefaultOps()
175
176 cliConf := readCliParams()
177
178 yamlConf, err := loadBBSimConf(cliConf.BBSim.ConfigFile)
179
180 if err != nil {
181 log.WithFields(log.Fields{
182 "file": cliConf.BBSim.ConfigFile,
183 "err": err,
184 }).Fatal("Can't read config file")
185 }
186
187 // merging Yaml and Default Values
188 if err := mergo.Merge(Config, yamlConf, mergo.WithOverride); err != nil {
189 log.WithFields(log.Fields{
190 "err": err,
191 }).Fatal("Can't merge YAML and Config")
192 }
193
194 // merging CLI values on top of the yaml ones
195 if err := mergo.Merge(Config, cliConf, mergo.WithOverride); err != nil {
196 log.WithFields(log.Fields{
197 "err": err,
198 }).Fatal("Can't merge CLI and Config")
199 }
200
201 services, err := loadBBSimServices(Config.BBSim.ServiceConfigFile)
202
203 if err != nil {
204 log.WithFields(log.Fields{
205 "file": Config.BBSim.ServiceConfigFile,
206 "err": err,
207 }).Fatal("Can't read services file")
208 }
209
210 Services = services
211
212}
213
214func readCliParams() *GlobalConfig {
215
Matteo Scandoloc11074d2020-09-14 14:59:24 -0700216 conf := getDefaultOps()
Matteo Scandolo4a036262020-08-17 15:56:13 -0700217
218 configFile := flag.String("config", conf.BBSim.ConfigFile, "Configuration file path")
219 servicesFile := flag.String("services", conf.BBSim.ServiceConfigFile, "Service Configuration file path")
220
221 olt_id := flag.Int("olt_id", conf.Olt.ID, "OLT device ID")
222 nni := flag.Int("nni", int(conf.Olt.NniPorts), "Number of NNI ports per OLT device to be emulated")
223 pon := flag.Int("pon", int(conf.Olt.PonPorts), "Number of PON ports per OLT device to be emulated")
224 onu := flag.Int("onu", int(conf.Olt.OnusPonPort), "Number of ONU devices per PON port to be emulated")
Matteo Scandolo93566702020-09-30 15:19:27 -0700225 oltRebootDelay := flag.Int("oltRebootDelay", conf.Olt.OltRebootDelay, "Time that BBSim should before restarting after a reboot")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700226
227 openolt_address := flag.String("openolt_address", conf.BBSim.OpenOltAddress, "IP address:port")
228 api_address := flag.String("api_address", conf.BBSim.ApiAddress, "IP address:port")
229 rest_api_address := flag.String("rest_api_address", conf.BBSim.RestApiAddress, "IP address:port")
amit.ghosh258d14c2020-10-02 15:13:38 +0200230 dmi_server_address := flag.String("dmi_server_address", conf.BBSim.DmiServerAddress, "IP address:port")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700231
232 profileCpu := flag.String("cpuprofile", "", "write cpu profile to file")
233
234 logLevel := flag.String("logLevel", conf.BBSim.LogLevel, "Set the log level (trace, debug, info, warn, error)")
235 logCaller := flag.Bool("logCaller", conf.BBSim.LogCaller, "Whether to print the caller filename or not")
236
237 delay := flag.Int("delay", conf.BBSim.Delay, "The delay between ONU DISCOVERY batches in milliseconds (1 ONU per each PON PORT at a time")
238
239 controlledActivation := flag.String("ca", conf.BBSim.ControlledActivation, "Set the mode for controlled activation of PON ports and ONUs")
240 enablePerf := flag.Bool("enableperf", conf.BBSim.EnablePerf, "Setting this flag will cause BBSim to not store data like traffic schedulers, flows of ONUs etc..")
241 enableEvents := flag.Bool("enableEvents", conf.BBSim.Events, "Enable sending BBSim events on configured kafka server")
242 kafkaAddress := flag.String("kafkaAddress", conf.BBSim.KafkaAddress, "IP:Port for kafka")
243 kafkaEventTopic := flag.String("kafkaEventTopic", conf.BBSim.KafkaEventTopic, "Ability to configure the topic on which BBSim publishes events on Kafka")
244 dhcpRetry := flag.Bool("dhcpRetry", conf.BBSim.DhcpRetry, "Set this flag if BBSim should retry DHCP upon failure until success")
245 authRetry := flag.Bool("authRetry", conf.BBSim.AuthRetry, "Set this flag if BBSim should retry EAPOL (Authentication) upon failure until success")
Matteo Scandolo93566702020-09-30 15:19:27 -0700246
Matteo Scandolo4a036262020-08-17 15:56:13 -0700247 flag.Parse()
248
249 conf.Olt.ID = int(*olt_id)
250 conf.Olt.NniPorts = uint32(*nni)
251 conf.Olt.PonPorts = uint32(*pon)
252 conf.Olt.OnusPonPort = uint32(*onu)
Matteo Scandolo93566702020-09-30 15:19:27 -0700253 conf.Olt.OltRebootDelay = *oltRebootDelay
Matteo Scandolo4a036262020-08-17 15:56:13 -0700254 conf.BBSim.ConfigFile = *configFile
255 conf.BBSim.ServiceConfigFile = *servicesFile
256 conf.BBSim.CpuProfile = profileCpu
257 conf.BBSim.LogLevel = *logLevel
258 conf.BBSim.LogCaller = *logCaller
259 conf.BBSim.Delay = *delay
260 conf.BBSim.ControlledActivation = *controlledActivation
261 conf.BBSim.EnablePerf = *enablePerf
262 conf.BBSim.Events = *enableEvents
263 conf.BBSim.KafkaAddress = *kafkaAddress
264 conf.BBSim.OpenOltAddress = *openolt_address
265 conf.BBSim.ApiAddress = *api_address
266 conf.BBSim.RestApiAddress = *rest_api_address
267 conf.BBSim.KafkaEventTopic = *kafkaEventTopic
268 conf.BBSim.AuthRetry = *authRetry
269 conf.BBSim.DhcpRetry = *dhcpRetry
amit.ghosh258d14c2020-10-02 15:13:38 +0200270 conf.BBSim.DmiServerAddress = *dmi_server_address
Matteo Scandolo4a036262020-08-17 15:56:13 -0700271
272 // update device id if not set
273 if conf.Olt.DeviceId == "" {
274 conf.Olt.DeviceId = net.HardwareAddr{0xA, 0xA, 0xA, 0xA, 0xA, byte(conf.Olt.ID)}.String()
275 }
276
Matteo Scandoloc11074d2020-09-14 14:59:24 -0700277 return conf
Matteo Scandolo4a036262020-08-17 15:56:13 -0700278}
279
280func getDefaultOps() *GlobalConfig {
281
282 c := &GlobalConfig{
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100283 BBSimConfig{
Matteo Scandolo4a036262020-08-17 15:56:13 -0700284 ConfigFile: "configs/bbsim.yaml",
285 ServiceConfigFile: "configs/att-services.yaml",
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100286 LogLevel: "debug",
287 LogCaller: false,
288 Delay: 200,
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100289 OpenOltAddress: ":50060",
290 ApiAddress: ":50070",
291 RestApiAddress: ":50071",
292 LegacyApiAddress: ":50072",
293 LegacyRestApiAddress: ":50073",
294 SadisRestAddress: ":50074",
295 SadisServer: true,
Pragya Arya324337e2020-02-20 14:35:08 +0530296 KafkaAddress: ":9092",
297 Events: false,
Pragya Arya2225f202020-01-29 18:05:01 +0530298 ControlledActivation: "default",
Anand S Katti09541352020-01-29 15:54:01 +0530299 EnablePerf: false,
Shrey Baid64cda472020-04-24 18:58:18 +0530300 KafkaEventTopic: "",
Shrey Baidf8abccc2020-06-15 19:41:22 +0530301 DhcpRetry: false,
302 AuthRetry: false,
amit.ghosh258d14c2020-10-02 15:13:38 +0200303 DmiServerAddress: ":50075",
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100304 },
305 OltConfig{
306 Vendor: "BBSim",
307 Model: "asfvolt16",
308 HardwareVersion: "emulated",
309 FirmwareVersion: "",
310 DeviceSerialNumber: "BBSM00000001",
311 PonPorts: 1,
312 NniPorts: 1,
313 OnusPonPort: 1,
314 Technology: "XGS-PON",
315 ID: 0,
Matteo Scandolo93566702020-09-30 15:19:27 -0700316 OltRebootDelay: 60,
Pragya Arya996a0892020-03-09 21:47:52 +0530317 PortStatsInterval: 20,
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100318 },
319 BBRConfig{
320 LogLevel: "debug",
321 LogCaller: false,
322 },
323 }
324 return c
325}
326
327// LoadBBSimConf loads the BBSim configuration from a YAML file
Matteo Scandolo4a036262020-08-17 15:56:13 -0700328func loadBBSimConf(filename string) (*GlobalConfig, error) {
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100329 yamlConfig := getDefaultOps()
330
331 yamlFile, err := ioutil.ReadFile(filename)
332 if err != nil {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700333 log.WithFields(log.Fields{
334 "err": err,
335 "filename": filename,
336 }).Error("Cannot load BBSim configuration file. Using defaults.")
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100337 return yamlConfig, nil
338 }
339
340 err = yaml.Unmarshal(yamlFile, yamlConfig)
341 if err != nil {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700342 return nil, err
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100343 }
344
345 return yamlConfig, nil
346}
347
Matteo Scandolo4a036262020-08-17 15:56:13 -0700348// LoadBBSimServices parses a file describing the services that need to be created for each UNI
349func loadBBSimServices(filename string) ([]ServiceYaml, error) {
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100350
Matteo Scandolo4a036262020-08-17 15:56:13 -0700351 yamlServiceCfg := YamlServiceConfig{}
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100352
Matteo Scandolo4a036262020-08-17 15:56:13 -0700353 yamlFile, err := ioutil.ReadFile(filename)
Matteo Scandolof65e6872020-04-15 15:18:43 -0700354 if err != nil {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700355 return nil, err
Matteo Scandolof65e6872020-04-15 15:18:43 -0700356 }
357
Matteo Scandolo4a036262020-08-17 15:56:13 -0700358 err = yaml.Unmarshal([]byte(yamlFile), &yamlServiceCfg)
Matteo Scandolof65e6872020-04-15 15:18:43 -0700359 if err != nil {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700360 return nil, err
Matteo Scandolof65e6872020-04-15 15:18:43 -0700361 }
362
Matteo Scandolo4a036262020-08-17 15:56:13 -0700363 for _, service := range yamlServiceCfg.Services {
364
365 if service.CTagAllocation == "" || service.STagAllocation == "" {
366 log.Fatal("c_tag_allocation and s_tag_allocation are mandatory fields")
367 }
368
369 if _, err := tagAllocationFromString(string(service.CTagAllocation)); err != nil {
370 log.WithFields(log.Fields{
371 "err": err,
372 }).Fatal("c_tag_allocation is not valid")
373 }
Matteo Scandolof65e6872020-04-15 15:18:43 -0700374 }
375
Matteo Scandolo4a036262020-08-17 15:56:13 -0700376 log.WithFields(log.Fields{
377 "services": yamlServiceCfg.String(),
378 }).Debug("BBSim services description correctly loaded")
379 return yamlServiceCfg.Services, nil
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700380}
381
Matteo Scandolo4a036262020-08-17 15:56:13 -0700382// This is only used by BBR
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700383func GetBBROpts() BBRCliOptions {
384
385 bbsimIp := flag.String("bbsimIp", "127.0.0.1", "BBSim IP")
386 bbsimPort := flag.String("bbsimPort", "50060", "BBSim Port")
387 bbsimApiPort := flag.String("bbsimApiPort", "50070", "BBSim API Port")
Matteo Scandolof5c537e2019-10-28 16:45:57 -0700388 logFile := flag.String("logfile", "", "Log to a file")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700389
Matteo Scandoloc11074d2020-09-14 14:59:24 -0700390 LoadConfig()
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700391
392 bbrOptions := BBRCliOptions{
Matteo Scandolo4a036262020-08-17 15:56:13 -0700393 Config,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700394 *bbsimIp,
395 *bbsimPort,
396 *bbsimApiPort,
Matteo Scandolof5c537e2019-10-28 16:45:57 -0700397 *logFile,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700398 }
399
400 return bbrOptions
401}