blob: 2fd5e9781b698fee45a491103c98b6f2788be573 [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001/*
Arda Demir20177532023-05-16 16:34:04 +03002 * Copyright 2019-2023 Ciena Corporation
Joey Armstrong903c69d2024-02-01 19:46:39 -05003 * Copyright 2019-2024 Open Networking Foundation (ONF) and the ONF Contributors
Zack Williamse940c7a2019-08-21 14:25:39 -07004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package commands
18
19import (
20 "context"
21 "fmt"
Scott Baker9173ed82020-05-19 08:30:12 -070022 "github.com/golang/protobuf/ptypes/empty"
Zack Williamse940c7a2019-08-21 14:25:39 -070023 flags "github.com/jessevdk/go-flags"
Scott Baker2b0ad652019-08-21 14:57:07 -070024 "github.com/opencord/voltctl/pkg/format"
Arda Demir20177532023-05-16 16:34:04 +030025 mtrs "github.com/opencord/voltha-lib-go/v7/pkg/meters"
David K. Bainbridgebd6b2882021-08-26 13:31:02 +000026 "github.com/opencord/voltha-protos/v5/go/openflow_13"
Arda Demir20177532023-05-16 16:34:04 +030027 tp_pb "github.com/opencord/voltha-protos/v5/go/tech_profile"
David K. Bainbridgebd6b2882021-08-26 13:31:02 +000028 "github.com/opencord/voltha-protos/v5/go/voltha"
Zack Williamse940c7a2019-08-21 14:25:39 -070029 "strings"
30)
31
32const (
Scott Baker9173ed82020-05-19 08:30:12 -070033 DEFAULT_LOGICAL_DEVICE_FORMAT = "table{{ .Id }}\t{{printf \"%016x\" .DatapathId}}\t{{.RootDeviceId}}\t{{.Desc.SerialNum}}\t{{.SwitchFeatures.NBuffers}}\t{{.SwitchFeatures.NTables}}\t{{printf \"0x%08x\" .SwitchFeatures.Capabilities}}"
Hardik Windlass9361bb82022-03-23 05:58:48 +000034 DEFAULT_LOGICAL_DEVICE_ORDER = "Id"
Scott Bakerb6f07692020-06-10 12:52:15 -070035 DEFAULT_LOGICAL_DEVICE_PORT_FORMAT = "table{{.Id}}\t{{.DeviceId}}\t{{.DevicePortNo}}\t{{.RootPort}}\t{{.OfpPortStats.PortNo}}\t{{.OfpPort.HwAddr}}\t{{.OfpPort.Name}}\t{{printf \"0x%08x\" .OfpPort.State}}\t{{printf \"0x%08x\" .OfpPort.Curr}}\t{{.OfpPort.CurrSpeed}}"
Arda Demir20177532023-05-16 16:34:04 +030036 DEFAULT_LOGICAL_DEVICE_METER_FORMAT = "table{{.MeterId}}\t{{.TrafficShaping.Cir}}\t{{.TrafficShaping.Cbs}}\t{{.TrafficShaping.Pir}}\t{{.TrafficShaping.Pbs}}\t{{.TrafficShaping.Gir}}"
37 DEFAULT_LOGICAL_DEVICE_METER_ORDER = "MeterId"
Zack Williamse940c7a2019-08-21 14:25:39 -070038 DEFAULT_LOGICAL_DEVICE_INSPECT_FORMAT = `ID: {{.Id}}
39 DATAPATHID: {{.DatapathId}}
40 ROOTDEVICEID: {{.RootDeviceId}}
Scott Baker9173ed82020-05-19 08:30:12 -070041 SERIALNUMNER: {{.Desc.SerialNum}}`
Zack Williamse940c7a2019-08-21 14:25:39 -070042)
43
44type LogicalDeviceId string
45
Arda Demir20177532023-05-16 16:34:04 +030046type LogicalDeviceMeterData struct {
47 MeterId uint32
48 TrafficShaping *tp_pb.TrafficShapingInfo
49}
50
Zack Williamse940c7a2019-08-21 14:25:39 -070051type LogicalDeviceList struct {
52 ListOutputOptions
53}
54
55type LogicalDeviceFlowList struct {
56 ListOutputOptions
Maninder045921e2020-09-29 16:46:02 +053057 FlowIdOptions
Zack Williamse940c7a2019-08-21 14:25:39 -070058 Args struct {
59 Id LogicalDeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
60 } `positional-args:"yes"`
61}
62
Himani Chawla3c161c62021-05-13 16:36:51 +053063type LogicalDeviceFlowGroupList struct {
64 ListOutputOptions
65 GroupListOptions
66 Args struct {
67 Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
68 } `positional-args:"yes"`
69}
70
Zack Williamse940c7a2019-08-21 14:25:39 -070071type LogicalDevicePortList struct {
72 ListOutputOptions
73 Args struct {
74 Id LogicalDeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
75 } `positional-args:"yes"`
76}
77
Arda Demir20177532023-05-16 16:34:04 +030078type LogicalDeviceMeterList struct {
79 ListOutputOptions
80 Args struct {
81 Id LogicalDeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
82 } `positional-args:"yes"`
83}
84
Zack Williamse940c7a2019-08-21 14:25:39 -070085type LogicalDeviceInspect struct {
86 OutputOptionsJson
87 Args struct {
88 Id LogicalDeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
89 } `positional-args:"yes"`
90}
91
92type LogicalDeviceOpts struct {
Himani Chawla3c161c62021-05-13 16:36:51 +053093 List LogicalDeviceList `command:"list"`
94 Flows LogicalDeviceFlowList `command:"flows"`
95 Groups LogicalDeviceFlowGroupList `command:"groups"`
96 Port struct {
kesavand12cd8eb2020-01-20 22:25:22 -050097 List LogicalDevicePortList `command:"list"`
98 } `command:"port"`
Arda Demir20177532023-05-16 16:34:04 +030099 Meters LogicalDeviceMeterList `command:"meters"`
100 Inspect LogicalDeviceInspect `command:"inspect"`
Zack Williamse940c7a2019-08-21 14:25:39 -0700101}
102
103var logicalDeviceOpts = LogicalDeviceOpts{}
104
105func RegisterLogicalDeviceCommands(parser *flags.Parser) {
David Bainbridge12f036f2019-10-15 22:09:04 +0000106 if _, err := parser.AddCommand("logicaldevice", "logical device commands", "Commands to query and manipulate VOLTHA logical devices", &logicalDeviceOpts); err != nil {
David Bainbridgea6722342019-10-24 23:55:53 +0000107 Error.Fatalf("Unexpected error while attempting to register logical device commands : %s", err)
David Bainbridge12f036f2019-10-15 22:09:04 +0000108 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700109}
110
111func (i *LogicalDeviceId) Complete(match string) []flags.Completion {
112 conn, err := NewConnection()
113 if err != nil {
114 return nil
115 }
116 defer conn.Close()
117
Scott Baker9173ed82020-05-19 08:30:12 -0700118 client := voltha.NewVolthaServiceClient(conn)
Zack Williamse940c7a2019-08-21 14:25:39 -0700119
David K. Bainbridge9189c632021-03-26 21:52:21 +0000120 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
Zack Williamse940c7a2019-08-21 14:25:39 -0700121 defer cancel()
122
Scott Baker9173ed82020-05-19 08:30:12 -0700123 logicalDevices, err := client.ListLogicalDevices(ctx, &empty.Empty{})
Zack Williamse940c7a2019-08-21 14:25:39 -0700124 if err != nil {
125 return nil
126 }
127
128 list := make([]flags.Completion, 0)
Scott Baker9173ed82020-05-19 08:30:12 -0700129 for _, item := range logicalDevices.Items {
130 if strings.HasPrefix(item.Id, match) {
131 list = append(list, flags.Completion{Item: item.Id})
Zack Williamse940c7a2019-08-21 14:25:39 -0700132 }
133 }
134
135 return list
136}
137
138func (options *LogicalDeviceList) Execute(args []string) error {
139
140 conn, err := NewConnection()
141 if err != nil {
142 return err
143 }
144 defer conn.Close()
145
Scott Baker9173ed82020-05-19 08:30:12 -0700146 client := voltha.NewVolthaServiceClient(conn)
Zack Williamse940c7a2019-08-21 14:25:39 -0700147
David K. Bainbridge9189c632021-03-26 21:52:21 +0000148 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
Zack Williamse940c7a2019-08-21 14:25:39 -0700149 defer cancel()
150
Scott Baker9173ed82020-05-19 08:30:12 -0700151 logicalDevices, err := client.ListLogicalDevices(ctx, &empty.Empty{})
Zack Williamse940c7a2019-08-21 14:25:39 -0700152 if err != nil {
153 return err
154 }
155
Scott Baker9173ed82020-05-19 08:30:12 -0700156 // Make sure json output prints an empty list, not "null"
157 if logicalDevices.Items == nil {
158 logicalDevices.Items = make([]*voltha.LogicalDevice, 0)
Zack Williamse940c7a2019-08-21 14:25:39 -0700159 }
160
161 outputFormat := CharReplacer.Replace(options.Format)
162 if outputFormat == "" {
David Bainbridgea6722342019-10-24 23:55:53 +0000163 outputFormat = GetCommandOptionWithDefault("logical-device-list", "format", DEFAULT_LOGICAL_DEVICE_FORMAT)
Zack Williamse940c7a2019-08-21 14:25:39 -0700164 }
165 if options.Quiet {
166 outputFormat = "{{.Id}}"
167 }
David Bainbridgea6722342019-10-24 23:55:53 +0000168 orderBy := options.OrderBy
169 if orderBy == "" {
Hardik Windlass9361bb82022-03-23 05:58:48 +0000170 orderBy = GetCommandOptionWithDefault("local-device-list", "order", DEFAULT_LOGICAL_DEVICE_ORDER)
David Bainbridgea6722342019-10-24 23:55:53 +0000171 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700172
Zack Williamse940c7a2019-08-21 14:25:39 -0700173 result := CommandResult{
174 Format: format.Format(outputFormat),
175 Filter: options.Filter,
David Bainbridgea6722342019-10-24 23:55:53 +0000176 OrderBy: orderBy,
Zack Williamse940c7a2019-08-21 14:25:39 -0700177 OutputAs: toOutputType(options.OutputAs),
178 NameLimit: options.NameLimit,
Scott Baker9173ed82020-05-19 08:30:12 -0700179 Data: logicalDevices.Items,
Zack Williamse940c7a2019-08-21 14:25:39 -0700180 }
181
182 GenerateOutput(&result)
183 return nil
184}
185
186func (options *LogicalDevicePortList) Execute(args []string) error {
187
188 conn, err := NewConnection()
189 if err != nil {
190 return err
191 }
192 defer conn.Close()
193
Scott Baker9173ed82020-05-19 08:30:12 -0700194 client := voltha.NewVolthaServiceClient(conn)
Zack Williamse940c7a2019-08-21 14:25:39 -0700195
David K. Bainbridge9189c632021-03-26 21:52:21 +0000196 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
Zack Williamse940c7a2019-08-21 14:25:39 -0700197 defer cancel()
198
Scott Baker9173ed82020-05-19 08:30:12 -0700199 id := voltha.ID{Id: string(options.Args.Id)}
Zack Williamse940c7a2019-08-21 14:25:39 -0700200
Scott Baker9173ed82020-05-19 08:30:12 -0700201 ports, err := client.ListLogicalDevicePorts(ctx, &id)
Zack Williamse940c7a2019-08-21 14:25:39 -0700202 if err != nil {
203 return err
204 }
205
Scott Bakerb6f07692020-06-10 12:52:15 -0700206 // ensure no nil pointers
207 for _, v := range ports.Items {
208 if v.OfpPortStats == nil {
209 v.OfpPortStats = &openflow_13.OfpPortStats{}
210 }
211 if v.OfpPort == nil {
212 v.OfpPort = &openflow_13.OfpPort{}
213 }
214 }
215
Zack Williamse940c7a2019-08-21 14:25:39 -0700216 outputFormat := CharReplacer.Replace(options.Format)
217 if outputFormat == "" {
David Bainbridgea6722342019-10-24 23:55:53 +0000218 outputFormat = GetCommandOptionWithDefault("logical-device-ports", "format", DEFAULT_LOGICAL_DEVICE_PORT_FORMAT)
Zack Williamse940c7a2019-08-21 14:25:39 -0700219 }
220 if options.Quiet {
221 outputFormat = "{{.Id}}"
222 }
David Bainbridgea6722342019-10-24 23:55:53 +0000223 orderBy := options.OrderBy
224 if orderBy == "" {
225 orderBy = GetCommandOptionWithDefault("logical-device-ports", "order", "")
226 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700227
Zack Williamse940c7a2019-08-21 14:25:39 -0700228 result := CommandResult{
229 Format: format.Format(outputFormat),
230 Filter: options.Filter,
David Bainbridgea6722342019-10-24 23:55:53 +0000231 OrderBy: orderBy,
Zack Williamse940c7a2019-08-21 14:25:39 -0700232 OutputAs: toOutputType(options.OutputAs),
233 NameLimit: options.NameLimit,
Scott Baker9173ed82020-05-19 08:30:12 -0700234 Data: ports.Items,
Zack Williamse940c7a2019-08-21 14:25:39 -0700235 }
236
237 GenerateOutput(&result)
238 return nil
239}
240
Arda Demir20177532023-05-16 16:34:04 +0300241func (options *LogicalDeviceMeterList) Execute(args []string) error {
242 conn, err := NewConnection()
243 if err != nil {
244 return err
245 }
246 defer conn.Close()
247
248 client := voltha.NewVolthaServiceClient(conn)
249
250 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
251 defer cancel()
252
253 id := voltha.ID{Id: string(options.Args.Id)}
254
255 meters, err := client.ListLogicalDeviceMeters(ctx, &id)
256 if err != nil {
257 return err
258 }
259
260 items := make([]*LogicalDeviceMeterData, 0)
261 for _, v := range meters.Items {
262 if v.Config == nil {
263 continue
264 }
265
266 data := &LogicalDeviceMeterData{}
267
268 data.MeterId = v.Config.MeterId
269 data.TrafficShaping, err = mtrs.GetTrafficShapingInfo(ctx, v.Config)
270 if err != nil {
271 return err
272 }
273
274 items = append(items, data)
275 }
276
277 outputFormat := CharReplacer.Replace(options.Format)
278 if outputFormat == "" {
279 outputFormat = GetCommandOptionWithDefault("logical-device-meters", "format", DEFAULT_LOGICAL_DEVICE_METER_FORMAT)
280 }
281 if options.Quiet {
282 outputFormat = "{{.MeterId}}"
283 }
284 orderBy := options.OrderBy
285 if orderBy == "" {
286 orderBy = GetCommandOptionWithDefault("logical-device-meters", "order", DEFAULT_LOGICAL_DEVICE_METER_ORDER)
287 }
288
289 result := CommandResult{
290 Format: format.Format(outputFormat),
291 Filter: options.Filter,
292 OrderBy: orderBy,
293 OutputAs: toOutputType(options.OutputAs),
294 NameLimit: options.NameLimit,
295 Data: items,
296 }
297
298 GenerateOutput(&result)
299 return nil
300}
301
Zack Williamse940c7a2019-08-21 14:25:39 -0700302func (options *LogicalDeviceFlowList) Execute(args []string) error {
303 fl := &FlowList{}
304 fl.ListOutputOptions = options.ListOutputOptions
Maninder045921e2020-09-29 16:46:02 +0530305 fl.FlowIdOptions = options.FlowIdOptions
Zack Williamse940c7a2019-08-21 14:25:39 -0700306 fl.Args.Id = string(options.Args.Id)
David Bainbridgea6722342019-10-24 23:55:53 +0000307 fl.Method = "logical-device-flows"
Zack Williamse940c7a2019-08-21 14:25:39 -0700308 return fl.Execute(args)
309}
310
Himani Chawla3c161c62021-05-13 16:36:51 +0530311func (options *LogicalDeviceFlowGroupList) Execute(args []string) error {
312 grp := &GroupList{}
313 grp.ListOutputOptions = options.ListOutputOptions
314 grp.GroupListOptions = options.GroupListOptions
315 grp.Args.Id = string(options.Args.Id)
316 grp.Method = "logical-device-groups"
317 return grp.Execute(args)
318
319}
320
Zack Williamse940c7a2019-08-21 14:25:39 -0700321func (options *LogicalDeviceInspect) Execute(args []string) error {
322 if len(args) > 0 {
323 return fmt.Errorf("only a single argument 'DEVICE_ID' can be provided")
324 }
325
326 conn, err := NewConnection()
327 if err != nil {
328 return err
329 }
330 defer conn.Close()
331
Scott Baker9173ed82020-05-19 08:30:12 -0700332 client := voltha.NewVolthaServiceClient(conn)
Zack Williamse940c7a2019-08-21 14:25:39 -0700333
David K. Bainbridge9189c632021-03-26 21:52:21 +0000334 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
Zack Williamse940c7a2019-08-21 14:25:39 -0700335 defer cancel()
336
Scott Baker9173ed82020-05-19 08:30:12 -0700337 id := voltha.ID{Id: string(options.Args.Id)}
Zack Williamse940c7a2019-08-21 14:25:39 -0700338
Scott Baker9173ed82020-05-19 08:30:12 -0700339 logicalDevice, err := client.GetLogicalDevice(ctx, &id)
Zack Williamse940c7a2019-08-21 14:25:39 -0700340 if err != nil {
341 return err
342 }
343
Zack Williamse940c7a2019-08-21 14:25:39 -0700344 outputFormat := CharReplacer.Replace(options.Format)
345 if outputFormat == "" {
David Bainbridgea6722342019-10-24 23:55:53 +0000346 outputFormat = GetCommandOptionWithDefault("logical-device-inspect", "format", DEFAULT_LOGICAL_DEVICE_INSPECT_FORMAT)
Zack Williamse940c7a2019-08-21 14:25:39 -0700347 }
348 if options.Quiet {
349 outputFormat = "{{.Id}}"
350 }
351
352 result := CommandResult{
353 Format: format.Format(outputFormat),
354 OutputAs: toOutputType(options.OutputAs),
355 NameLimit: options.NameLimit,
Scott Baker9173ed82020-05-19 08:30:12 -0700356 Data: logicalDevice,
Zack Williamse940c7a2019-08-21 14:25:39 -0700357 }
358 GenerateOutput(&result)
359 return nil
360}