Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2022-present Open Networking Foundation |
| 3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | * you may not use this file except in compliance with the License. |
| 5 | * You may obtain a copy of the License at |
| 6 | * |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | * |
| 9 | * Unless required by applicable law or agreed to in writing, software |
| 10 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | * See the License for the specific language governing permissions and |
| 13 | * limitations under the License. |
| 14 | */ |
| 15 | |
| 16 | package application |
| 17 | |
| 18 | import ( |
| 19 | "encoding/json" |
| 20 | "errors" |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 21 | "context" |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 22 | "sync" |
| 23 | |
| 24 | cntlr "voltha-go-controller/internal/pkg/controller" |
| 25 | "voltha-go-controller/database" |
| 26 | "voltha-go-controller/internal/pkg/of" |
Tinoj Joseph | 1d10832 | 2022-07-13 10:07:39 +0530 | [diff] [blame] | 27 | "voltha-go-controller/log" |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 28 | ) |
| 29 | |
| 30 | // VoltShaperConfig is shaper profile configuration structure |
| 31 | type VoltShaperConfig struct { |
| 32 | Name string |
| 33 | BurstSize uint32 |
| 34 | } |
| 35 | |
| 36 | // VoltBwConfig is bandwidth profile configuration structure |
| 37 | type VoltBwConfig struct { |
| 38 | Name string |
| 39 | Fir uint32 |
| 40 | Air uint32 |
| 41 | Eir uint32 |
| 42 | } |
| 43 | |
| 44 | // VoltBandwidthProf is bandwidth profile stored at VGC |
| 45 | type VoltBandwidthProf struct { |
| 46 | VoltBwConfig |
| 47 | } |
| 48 | |
| 49 | // VoltShaperProf is shaper profile stored at VGC |
| 50 | type VoltShaperProf struct { |
| 51 | VoltShaperConfig |
| 52 | } |
| 53 | |
| 54 | // VoltMeterProf is meter profile stored at VGC |
| 55 | type VoltMeterProf struct { |
| 56 | VoltMeter |
| 57 | } |
| 58 | |
| 59 | // MeterMgr structure |
| 60 | type MeterMgr struct { |
| 61 | Meters sync.Map |
| 62 | MetersByID sync.Map |
| 63 | LastMeterID uint32 |
| 64 | } |
| 65 | |
| 66 | // Init to initialize MeterMgr |
| 67 | func (m *MeterMgr) Init() { |
| 68 | m.LastMeterID = 0 |
| 69 | } |
| 70 | |
| 71 | // VoltMeter : A VOLT meter is a combination of BW and shaper profiles |
| 72 | // The ID is generated by the VOLT application |
| 73 | type VoltMeter struct { |
| 74 | Name string |
| 75 | ID uint32 |
| 76 | Fir uint32 |
| 77 | Air uint32 |
| 78 | Eir uint32 |
| 79 | BurstSize uint32 |
| 80 | AssociatedServices uint32 |
| 81 | Version string |
| 82 | Cir uint32 |
| 83 | Cbs uint32 |
| 84 | Pir uint32 |
| 85 | Pbs uint32 |
| 86 | Gir uint32 |
| 87 | Ebs uint32 |
| 88 | } |
| 89 | |
| 90 | // WriteToDb to write a meter profile to DB |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 91 | func (vm *VoltMeter) WriteToDb(cntx context.Context) error { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 92 | vm.Version = database.PresentVersionMap[database.MeterPath] |
| 93 | b, err := json.Marshal(vm) |
| 94 | if err != nil { |
| 95 | return err |
| 96 | } |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 97 | if err1 := db.PutMeter(cntx, vm.Name, string(b)); err1 != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 98 | return err1 |
| 99 | } |
| 100 | return nil |
| 101 | } |
| 102 | |
| 103 | // DelFromDb to delete a meter profile from DB |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 104 | func (vm *VoltMeter) DelFromDb(cntx context.Context) { |
| 105 | _ = db.DelMeter(cntx, vm.Name) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | // GetMeterByName to get meter by name |
| 109 | func (m *MeterMgr) GetMeterByName(name string) (*VoltMeter, bool) { |
| 110 | meter, ok := m.Meters.Load(name) |
| 111 | logger.Infow(ctx, "Meter Obtained Name", log.Fields{"Meter": meter}) |
| 112 | if ok { |
| 113 | return meter.(*VoltMeter), ok |
| 114 | } |
| 115 | return nil, ok |
| 116 | } |
| 117 | |
| 118 | // GetMeterByID to get meter by ID |
| 119 | func (m *MeterMgr) GetMeterByID(id uint32) (*VoltMeter, bool) { |
| 120 | meter, ok := m.MetersByID.Load(id) |
| 121 | logger.Infow(ctx, "Meter Obtained ID", log.Fields{"Meter": meter}) |
| 122 | if ok { |
| 123 | return meter.(*VoltMeter), ok |
| 124 | } |
| 125 | return nil, ok |
| 126 | } |
| 127 | |
| 128 | // AddMeter to add meter |
| 129 | func (m *MeterMgr) AddMeter(meter *VoltMeter) { |
| 130 | m.Meters.Store(meter.Name, meter) |
| 131 | m.MetersByID.Store(meter.ID, meter) |
| 132 | logger.Infow(ctx, "Meter Added/Updated", log.Fields{"Meter": meter, "Name": meter.Name, "Id": meter.ID}) |
| 133 | } |
| 134 | |
| 135 | // DelMeter to delete meter |
| 136 | func (m *MeterMgr) DelMeter(meter *VoltMeter) { |
| 137 | m.Meters.Delete(meter.Name) |
| 138 | m.MetersByID.Delete(meter.ID) |
| 139 | logger.Infow(ctx, "Meter Deleted", log.Fields{"Meter": meter, "Name": meter.Name, "Id": meter.ID}) |
| 140 | } |
| 141 | |
| 142 | // AddToDevice to add meter to the device |
| 143 | func (vm *VoltMeter) AddToDevice(port string, device string, aggVM *VoltMeter) { |
| 144 | logger.Debugw(ctx, "Adding Meter To Device", log.Fields{"Id": vm.ID, "Device": device, "Port": port}) |
| 145 | meter := of.NewMeter(vm.ID) |
| 146 | // meter.AddBand(vm.Air, vm.BurstSize) |
| 147 | // meter.AddBand(vm.Eir, vm.BurstSize) |
| 148 | // if aggVM != nil { |
| 149 | // meter.AddBand(aggVM.Air, aggVM.BurstSize) |
| 150 | // meter.AddBand(aggVM.Eir, aggVM.BurstSize) |
| 151 | // } |
| 152 | |
| 153 | //Community VGC Impl |
| 154 | |
| 155 | //Set Cir |
| 156 | if vm.Cir != 0 { |
| 157 | meter.AddBand(vm.Cir, vm.Cbs) |
| 158 | } |
| 159 | |
| 160 | //Set Air to 0 if both air & gir are set |
| 161 | if vm.Air != 0 && vm.Gir != 0 { |
| 162 | vm.Air = 0 |
| 163 | } |
| 164 | |
| 165 | //Set Pir & Pbs |
| 166 | var pir uint32 |
| 167 | var pbs uint32 |
| 168 | if vm.Pir != 0 { |
| 169 | pir = vm.Pir |
| 170 | } else { |
| 171 | pir = vm.Eir + vm.Cir + vm.Gir + vm.Air |
| 172 | } |
| 173 | |
| 174 | if vm.Pbs != 0 { |
| 175 | pbs = vm.Pbs |
| 176 | } else { |
| 177 | pbs = vm.Ebs + vm.Cbs |
| 178 | } |
| 179 | meter.AddBand(pir, pbs) |
| 180 | |
| 181 | //Set Gir |
| 182 | if vm.Gir != 0 { |
| 183 | meter.AddBand(vm.Gir, 0) |
| 184 | } |
| 185 | |
| 186 | logger.Infow(ctx, "Meter Config", log.Fields{"Cir": vm.Cir, "Air": vm.Air, "Pir": vm.Pir, "Gir": vm.Gir, "Eir": vm.Eir}) |
| 187 | logger.Infow(ctx, "Meter Burst Config", log.Fields{"Cbs": vm.Cbs, "Pbs": vm.Pbs}) |
| 188 | logger.Infow(ctx, "Meter Burst Oper", log.Fields{"Pir": pir, "Pbs": pbs}) |
| 189 | //Set Air |
| 190 | // Air is used in place of Gir only if Gir is |
| 191 | // not present and Air is not 0 |
| 192 | if vm.Air != 0 { |
| 193 | meter.AddBand(vm.Air, 0) |
| 194 | } |
| 195 | |
Tinoj Joseph | 1d10832 | 2022-07-13 10:07:39 +0530 | [diff] [blame] | 196 | logger.Debugw(ctx, "Total Bands are", log.Fields{"meter": *meter}) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 197 | if err := cntlr.GetController().ModMeter(port, device, of.MeterCommandAdd, meter); err != nil { |
| 198 | logger.Warnw(ctx, "Add meter to device Failed", log.Fields{"Id": vm.ID, "meter": *meter, "Error": err}) |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | // AddMeterToDevice to add meter to the device |
| 203 | func (m *MeterMgr) AddMeterToDevice(port string, device string, meterID uint32, aggMeterID uint32) { |
| 204 | var aggVM *VoltMeter |
| 205 | vm, err := m.GetMeterByProfID(meterID) |
| 206 | if err == nil { |
| 207 | if 0 != aggMeterID { //Assuming valid meter id will never be 0 |
| 208 | if aggVM, err = m.GetMeterByProfID(aggMeterID); err != nil { |
| 209 | logger.Warnw(ctx, "Aggregated Meter not found", log.Fields{"Id": aggMeterID}) |
| 210 | } |
| 211 | } |
| 212 | vm.AddToDevice(port, device, aggVM) |
| 213 | } else { |
| 214 | logger.Warnw(ctx, "Meter not found", log.Fields{"Id": meterID}) |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | // RestoreMetersFromDb to read from the DB and restore all the services |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 219 | func (m *MeterMgr) RestoreMetersFromDb(cntx context.Context) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 220 | // VNETS must be learnt first |
| 221 | logger.Infow(ctx, "LastMeterID on restart", log.Fields{"LastMeterID": m.LastMeterID}) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 222 | ms, _ := db.GetMeters(cntx) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 223 | for _, mt := range ms { |
| 224 | b, ok := mt.Value.([]byte) |
| 225 | if !ok { |
| 226 | logger.Warn(ctx, "The value type is not []byte") |
| 227 | continue |
| 228 | } |
| 229 | var meter VoltMeter |
| 230 | err := json.Unmarshal(b, &meter) |
| 231 | if err != nil { |
| 232 | logger.Warn(ctx, "Unmarshal of meter profile failed") |
| 233 | continue |
| 234 | } |
| 235 | logger.Infow(ctx, "Retrieved Meter", log.Fields{"Meter": meter.Name}) |
| 236 | m.AddMeter(&meter) |
| 237 | if meter.ID > m.LastMeterID { |
| 238 | m.LastMeterID = meter.ID |
| 239 | } |
| 240 | } |
| 241 | logger.Infow(ctx, "LastMeterID on reading DB", log.Fields{"LastMeterID": m.LastMeterID}) |
| 242 | } |
| 243 | |
| 244 | // AddMeterProf to add the meter profile name as key |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 245 | func (va *VoltApplication) AddMeterProf(cntx context.Context, cfg VoltMeter) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 246 | |
| 247 | mm := &va.MeterMgr |
| 248 | if _, ok := mm.GetMeterByName(cfg.Name); ok { |
| 249 | logger.Warnw(ctx, "Meter profile exists", log.Fields{"Name": cfg.Name}) |
| 250 | return |
| 251 | } |
| 252 | |
| 253 | mm.LastMeterID++ |
| 254 | //FIX-ME: Hardcoded the meter-id temp till meter delete is introduced |
| 255 | //Restriction: Only one meter profile should be used across all services |
| 256 | // id := uint32(1) //mm.LastMeterId |
| 257 | id := mm.LastMeterID |
| 258 | cfg.ID = id |
| 259 | mm.AddMeter(&cfg) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 260 | if err := cfg.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 261 | logger.Warnw(ctx, "MeterProf Write to DB Failed", log.Fields{"MeterConfig": cfg, "Error": err}) |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | // UpdateMeterProf to update the meter profile |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 266 | func (va *VoltApplication) UpdateMeterProf(cntx context.Context, cfg VoltMeter) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 267 | mm := &va.MeterMgr |
| 268 | if _, ok := mm.GetMeterByName(cfg.Name); !ok { |
| 269 | logger.Warnw(ctx, "Meter profile does not exist", log.Fields{"Name": cfg.Name}) |
| 270 | return |
| 271 | } |
| 272 | mm.AddMeter(&cfg) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 273 | if err := cfg.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 274 | logger.Warnw(ctx, "MeterProf Write to DB Failed", log.Fields{"MeterConfig": cfg, "Error": err}) |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | // GetMeterByProfID to get a meter based on the identities of bandwidth profile and shaper |
| 279 | // profile names. |
| 280 | func (m *MeterMgr) GetMeterByProfID(id uint32) (*VoltMeter, error) { |
| 281 | if mtr, ok := m.GetMeterByID(id); ok { |
| 282 | return mtr, nil |
| 283 | } |
| 284 | return nil, errors.New("Meter Missing") |
| 285 | } |
| 286 | |
| 287 | // GetMeter to get a meter based on the identities of bandwidth profile and shaper |
| 288 | // profile names. |
| 289 | func (m *MeterMgr) GetMeter(meterID string) (*VoltMeter, error) { |
| 290 | if mt, ok := m.GetMeterByName(meterID); ok { |
| 291 | return mt, nil |
| 292 | } |
| 293 | return nil, errors.New("Meter Missing") |
| 294 | } |
| 295 | |
| 296 | // DeleteFromDevice to delete meter from the device |
| 297 | func (vm *VoltMeter) DeleteFromDevice(port string, device string) { |
| 298 | |
| 299 | meter := of.NewMeter(vm.ID) |
| 300 | |
| 301 | logger.Debugw(ctx, "Delete meter from device", log.Fields{"Id": vm.ID, "meter": *meter}) |
| 302 | if err := cntlr.GetController().ModMeter(port, device, of.MeterCommandDel, meter); err != nil { |
| 303 | logger.Warnw(ctx, "Delete meter from device Failed", log.Fields{"Id": vm.ID, "meter": *meter, "Error": err}) |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | // DelMeterProf to delete meter profile |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 308 | func (va *VoltApplication) DelMeterProf(cntx context.Context, name string) error { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 309 | mm := &va.MeterMgr |
| 310 | if _, ok := mm.GetMeterByName(name); !ok { |
| 311 | logger.Warnw(ctx, "Meter profile does not exist", log.Fields{"Name": name}) |
| 312 | return errors.New("Meter profile doesn't exist") |
| 313 | } |
| 314 | cfg, _ := mm.GetMeterByName(name) |
| 315 | if cfg.AssociatedServices != 0 { |
| 316 | logger.Warnw(ctx, "Mismatch in submgr and vgc oeter profile service reference", |
| 317 | log.Fields{"MeterProfile": name, "serviceCount": cfg.AssociatedServices}) |
| 318 | return errors.New("Service reference is not 0") |
| 319 | } |
| 320 | //TODO : delete from all devices |
| 321 | delmeterFromDevice := func(key interface{}, value interface{}) bool { |
| 322 | device := key.(string) |
| 323 | port, _ := GetApplication().GetNniPort(device) |
| 324 | cfg.DeleteFromDevice(port, device) |
| 325 | return true |
| 326 | } |
| 327 | va.DevicesDisc.Range(delmeterFromDevice) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 328 | cfg.DelFromDb(cntx) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 329 | //Delete meter from device will be invoked by caller separately |
| 330 | mm.DelMeter(cfg) |
| 331 | return nil |
| 332 | } |