blob: 8869c057750efc5080b6d0fe62a2ff8cfac07af3 [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001/*
2 * Copyright 2019-present Ciena Corporation
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 */
16package model
17
18import (
19 "fmt"
David K. Bainbridgebd6b2882021-08-26 13:31:02 +000020 "github.com/opencord/voltha-protos/v5/go/openflow_13"
Zack Williamse940c7a2019-08-21 14:25:39 -070021)
22
23type FlowFieldFlag uint64
24
25const (
Zack Williamse940c7a2019-08-21 14:25:39 -070026 // Define bit flags for flow fields to determine what is set and
27 // what is not
28 FLOW_FIELD_UNSUPPORTED_MATCH FlowFieldFlag = 1 << iota
29 FLOW_FIELD_UNSUPPORTED_INSTRUCTION
30 FLOW_FIELD_UNSUPPORTED_ACTION
31 FLOW_FIELD_UNSUPPORTED_SET_FIELD
32 FLOW_FIELD_ID
33 FLOW_FIELD_TABLE_ID
34 FLOW_FIELD_DURATION_SEC
35 FLOW_FIELD_DURATION_NSEC
36 FLOW_FIELD_IDLE_TIMEOUT
37 FLOW_FIELD_HARD_TIMEOUT
38 FLOW_FIELD_PACKET_COUNT
39 FLOW_FIELD_BYTE_COUNT
40 FLOW_FIELD_PRIORITY
41 FLOW_FIELD_COOKIE
42 FLOW_FIELD_IN_PORT
43 FLOW_FIELD_ETH_TYPE
44 FLOW_FIELD_VLAN_ID
45 FLOW_FIELD_IP_PROTO
46 FLOW_FIELD_UDP_SRC
47 FLOW_FIELD_UDP_DST
48 FLOW_FIELD_METADATA
49 FLOW_FIELD_SET_VLAN_ID
50 FLOW_FIELD_POP_VLAN
51 FLOW_FIELD_PUSH_VLAN_ID
52 FLOW_FIELD_OUTPUT
53 FLOW_FIELD_GOTO_TABLE
David Bainbridge09c61672019-08-23 19:07:54 +000054 FLOW_FIELD_WRITE_METADATA
Zack Williamse940c7a2019-08-21 14:25:39 -070055 FLOW_FIELD_CLEAR_ACTIONS
David Bainbridge09c61672019-08-23 19:07:54 +000056 FLOW_FIELD_METER
Zack Williamse940c7a2019-08-21 14:25:39 -070057 FLOW_FIELD_TUNNEL_ID
58 FLOW_FIELD_VLAN_PCP
59
60 FLOW_FIELD_HEADER = FLOW_FIELD_ID | FLOW_FIELD_TABLE_ID |
61 FLOW_FIELD_PRIORITY | FLOW_FIELD_COOKIE
62
63 FLOW_FIELD_STATS = FLOW_FIELD_DURATION_SEC | FLOW_FIELD_DURATION_NSEC |
64 FLOW_FIELD_IDLE_TIMEOUT | FLOW_FIELD_HARD_TIMEOUT |
65 FLOW_FIELD_PACKET_COUNT | FLOW_FIELD_BYTE_COUNT
Andrea Campanella086629f2020-02-21 14:15:43 +010066
67 //ReservedVlan Transparent Vlan (Masked Vlan, VLAN_ANY in ONOS Flows)
68 ReservedTransparentVlan = 4096
Zack Williamse940c7a2019-08-21 14:25:39 -070069)
70
71var (
72 // Provide an array of all flags that can be used for iteration
73 AllFlowFieldFlags = []FlowFieldFlag{
74 FLOW_FIELD_UNSUPPORTED_MATCH,
75 FLOW_FIELD_UNSUPPORTED_INSTRUCTION,
76 FLOW_FIELD_UNSUPPORTED_ACTION,
77 FLOW_FIELD_UNSUPPORTED_SET_FIELD,
78 FLOW_FIELD_ID,
79 FLOW_FIELD_TABLE_ID,
80 FLOW_FIELD_DURATION_SEC,
81 FLOW_FIELD_DURATION_NSEC,
82 FLOW_FIELD_IDLE_TIMEOUT,
83 FLOW_FIELD_HARD_TIMEOUT,
84 FLOW_FIELD_PACKET_COUNT,
85 FLOW_FIELD_BYTE_COUNT,
86 FLOW_FIELD_PRIORITY,
87 FLOW_FIELD_COOKIE,
88 FLOW_FIELD_IN_PORT,
89 FLOW_FIELD_ETH_TYPE,
90 FLOW_FIELD_VLAN_ID,
91 FLOW_FIELD_IP_PROTO,
92 FLOW_FIELD_UDP_SRC,
93 FLOW_FIELD_UDP_DST,
94 FLOW_FIELD_METADATA,
95 FLOW_FIELD_SET_VLAN_ID,
96 FLOW_FIELD_POP_VLAN,
97 FLOW_FIELD_PUSH_VLAN_ID,
98 FLOW_FIELD_OUTPUT,
99 FLOW_FIELD_GOTO_TABLE,
David Bainbridge09c61672019-08-23 19:07:54 +0000100 FLOW_FIELD_WRITE_METADATA,
Zack Williamse940c7a2019-08-21 14:25:39 -0700101 FLOW_FIELD_CLEAR_ACTIONS,
David Bainbridge09c61672019-08-23 19:07:54 +0000102 FLOW_FIELD_METER,
Zack Williamse940c7a2019-08-21 14:25:39 -0700103 FLOW_FIELD_TUNNEL_ID,
104 FLOW_FIELD_VLAN_PCP,
105 }
106)
107
108func (f *FlowFieldFlag) Count() int {
109 var count int
110 var bit uint64 = 1
111 var asUint64 = uint64(*f)
112 for i := 0; i < 64; i += 1 {
113 if asUint64&bit > 0 {
114 count += 1
115 }
116 bit <<= 1
117 }
118 return count
119}
120func (f *FlowFieldFlag) IsSet(flag FlowFieldFlag) bool {
121 return *f&flag > 0
122}
123
124func (f *FlowFieldFlag) Set(flag FlowFieldFlag) {
125 *f |= flag
126}
127
128func (f *FlowFieldFlag) Clear(flag FlowFieldFlag) {
129 var mask = ^(flag)
130 *f &= mask
131}
132
133func (f *FlowFieldFlag) Reset() {
134 *f = 0
135}
136
137func (f FlowFieldFlag) String() string {
138 switch f {
139 case FLOW_FIELD_UNSUPPORTED_MATCH:
140 return "UnsupportedMatch"
141 case FLOW_FIELD_UNSUPPORTED_INSTRUCTION:
142 return "UnsupportedInstruction"
143 case FLOW_FIELD_UNSUPPORTED_ACTION:
144 return "UnsupportedAction"
145 case FLOW_FIELD_UNSUPPORTED_SET_FIELD:
146 return "UnsupportedSetField"
147 case FLOW_FIELD_ID:
148 return "Id"
149 case FLOW_FIELD_TABLE_ID:
150 return "TableId"
151 case FLOW_FIELD_DURATION_SEC:
152 return "DurationSec"
153 case FLOW_FIELD_DURATION_NSEC:
154 return "DurationNsec"
155 case FLOW_FIELD_IDLE_TIMEOUT:
156 return "IdleTimeout"
157 case FLOW_FIELD_HARD_TIMEOUT:
158 return "HardTimeout"
159 case FLOW_FIELD_PACKET_COUNT:
160 return "PacketCount"
161 case FLOW_FIELD_BYTE_COUNT:
162 return "ByteCount"
163 case FLOW_FIELD_PRIORITY:
164 return "Priority"
165 case FLOW_FIELD_COOKIE:
166 return "Cookie"
167 case FLOW_FIELD_IN_PORT:
168 return "InPort"
169 case FLOW_FIELD_ETH_TYPE:
170 return "EthType"
171 case FLOW_FIELD_VLAN_ID:
172 return "VlanId"
173 case FLOW_FIELD_IP_PROTO:
174 return "IpProto"
175 case FLOW_FIELD_UDP_SRC:
176 return "UdpSrc"
177 case FLOW_FIELD_UDP_DST:
178 return "UdpDst"
179 case FLOW_FIELD_METADATA:
180 return "Metadata"
181 case FLOW_FIELD_SET_VLAN_ID:
182 return "SetVlanId"
183 case FLOW_FIELD_POP_VLAN:
184 return "PopVlan"
185 case FLOW_FIELD_PUSH_VLAN_ID:
186 return "PushVlanId"
187 case FLOW_FIELD_OUTPUT:
188 return "Output"
189 case FLOW_FIELD_GOTO_TABLE:
190 return "GotoTable"
David Bainbridge09c61672019-08-23 19:07:54 +0000191 case FLOW_FIELD_WRITE_METADATA:
192 return "WriteMetadata"
Zack Williamse940c7a2019-08-21 14:25:39 -0700193 case FLOW_FIELD_CLEAR_ACTIONS:
194 return "ClearActions"
David Bainbridge09c61672019-08-23 19:07:54 +0000195 case FLOW_FIELD_METER:
196 return "MeterId"
Zack Williamse940c7a2019-08-21 14:25:39 -0700197 case FLOW_FIELD_TUNNEL_ID:
198 return "TunnelId"
199 case FLOW_FIELD_VLAN_PCP:
200 return "VlanPcp"
201 default:
202 return "UnknownFieldFlag"
203 }
204}
205
206/*
207 * This is a partial list of OF match/action values. This list will be
208 * expanded as new fields are needed within VOLTHA
209 *
210 * Strings are used in the output structure so that on output the table
211 * can be "sparsely" populated with "empty" cells as opposed to 0 (zeros)
212 * all over the place.
213 */
214type Flow struct {
215 Id string `json:"id"`
216 TableId uint32 `json:"tableid"`
217 DurationSec uint32 `json:"durationsec"`
218 DurationNsec uint32 `json:"durationnsec"`
219 IdleTimeout uint32 `json:"idletimeout"`
220 HardTimeout uint32 `json:"hardtimeout"`
221 PacketCount uint64 `json:"packetcount"`
222 ByteCount uint64 `json:"bytecount"`
223 Priority uint32 `json:"priority"`
224 Cookie string `json:"cookie"`
225 UnsupportedMatch string `json:"unsupportedmatch,omitempty"`
226 InPort string `json:"inport,omitempty"`
227 EthType string `json:"ethtype,omitempty"`
228 VlanId string `json:"vlanid,omitempty"`
229 IpProto string `json:"ipproto,omitempty"`
230 UdpSrc string `json:"udpsrc,omitempty"`
231 UdpDst string `json:"dstsrc,omitempty"`
232 Metadata string `json:"metadata,omitempty"`
233 UnsupportedInstruction string `json:"unsupportedinstruction,omitempty"`
234 UnsupportedAction string `json:"unsupportedaction,omitempty"`
235 UnsupportedSetField string `json:"unsupportedsetfield,omitempty"`
236 SetVlanId string `json:"setvlanid,omitempty"`
237 PopVlan string `json:"popvlan,omitempty"`
238 PushVlanId string `json:"pushvlanid,omitempty"`
239 Output string `json:"output,omitempty"`
240 GotoTable string `json:"gototable,omitempty"`
David Bainbridge09c61672019-08-23 19:07:54 +0000241 WriteMetadata string `json:"writemetadata,omitempty"`
Zack Williamse940c7a2019-08-21 14:25:39 -0700242 ClearActions string `json:"clear,omitempty"`
David Bainbridge09c61672019-08-23 19:07:54 +0000243 MeterId string `json:"meter,omitempty"`
Zack Williamse940c7a2019-08-21 14:25:39 -0700244 TunnelId string `json:"tunnelid,omitempty"`
245 VlanPcp string `json:"vlanpcp,omitempty"`
246
247 populated FlowFieldFlag
248}
249
250func (f *Flow) Count() int {
251 return f.populated.Count()
252}
253
254func (f *Flow) IsSet(flag FlowFieldFlag) bool {
255 return f.populated.IsSet(flag)
256}
257
258func (f *Flow) Set(flag FlowFieldFlag) {
259 f.populated.Set(flag)
260}
261
262func (f *Flow) Clear(flag FlowFieldFlag) {
263 f.populated.Clear(flag)
264}
265
266func (f *Flow) Reset() {
267 f.populated.Reset()
268}
269
270func (f *Flow) Populated() FlowFieldFlag {
271 return f.populated
272}
273
274func toVlanId(vid uint32) string {
275 if vid == 0 {
276 return "untagged"
277 } else if vid&0x1000 > 0 {
278 return fmt.Sprintf("%d", vid-4096)
279 }
280 return fmt.Sprintf("%d", vid)
281}
282
283func appendInt32(base string, val int32) string {
284 if len(base) > 0 {
285 return fmt.Sprintf("%s,%d", base, val)
286 }
287 return fmt.Sprintf("%d", val)
288}
289
290func appendUint32(base string, val uint32) string {
291 if len(base) > 0 {
292 return fmt.Sprintf("%s,%d", base, val)
293 }
294 return fmt.Sprintf("%d", val)
295}
296
Maninder045921e2020-09-29 16:46:02 +0530297func (f *Flow) PopulateFromProto(flow *openflow_13.OfpFlowStats, hexId bool) {
Zack Williamse940c7a2019-08-21 14:25:39 -0700298
299 f.Reset()
Maninder045921e2020-09-29 16:46:02 +0530300 if hexId {
301 f.Id = fmt.Sprintf("%016x", flow.Id)
302 } else {
303 f.Id = fmt.Sprintf("%v", flow.Id)
304 }
305
Scott Baker9173ed82020-05-19 08:30:12 -0700306 f.TableId = flow.TableId
307 f.Priority = flow.Priority
Zack Williamse940c7a2019-08-21 14:25:39 -0700308 // mask the lower 8 for the cookie, why?
Scott Baker9173ed82020-05-19 08:30:12 -0700309 cookie := flow.Cookie
Zack Williamse940c7a2019-08-21 14:25:39 -0700310 if cookie == 0 {
311 f.Cookie = "0"
312 } else {
Scott Baker9173ed82020-05-19 08:30:12 -0700313 f.Cookie = fmt.Sprintf("~%08x", flow.Cookie&0xffffffff)
Zack Williamse940c7a2019-08-21 14:25:39 -0700314 }
Scott Baker9173ed82020-05-19 08:30:12 -0700315 f.DurationSec = flow.DurationSec
316 f.DurationNsec = flow.DurationNsec
317 f.IdleTimeout = flow.IdleTimeout
318 f.HardTimeout = flow.HardTimeout
319 f.PacketCount = flow.PacketCount
320 f.ByteCount = flow.ByteCount
Zack Williamse940c7a2019-08-21 14:25:39 -0700321 f.Set(FLOW_FIELD_HEADER | FLOW_FIELD_STATS)
322
Scott Baker9173ed82020-05-19 08:30:12 -0700323 for _, field := range flow.Match.OxmFields {
Zack Williamse940c7a2019-08-21 14:25:39 -0700324 // Only support OFPXMC_OPENFLOW_BASIC (0x8000)
Scott Baker9173ed82020-05-19 08:30:12 -0700325 if field.OxmClass != 0x8000 {
Zack Williamse940c7a2019-08-21 14:25:39 -0700326 continue
327 }
328
Scott Baker9173ed82020-05-19 08:30:12 -0700329 basic := field.GetOfbField()
330
331 switch basic.Type {
Zack Williamse940c7a2019-08-21 14:25:39 -0700332 case 0: // IN_PORT
333 f.Set(FLOW_FIELD_IN_PORT)
Scott Baker9173ed82020-05-19 08:30:12 -0700334 f.InPort = fmt.Sprintf("%d", basic.GetPort())
Zack Williamse940c7a2019-08-21 14:25:39 -0700335 case 2: // METADATA
336 f.Set(FLOW_FIELD_METADATA)
Scott Baker9173ed82020-05-19 08:30:12 -0700337 f.Metadata = fmt.Sprintf("0x%016x", basic.GetTableMetadata())
Zack Williamse940c7a2019-08-21 14:25:39 -0700338 case 5: // ETH_TYPE
339 f.Set(FLOW_FIELD_ETH_TYPE)
Scott Baker9173ed82020-05-19 08:30:12 -0700340 f.EthType = fmt.Sprintf("0x%04x", basic.GetEthType())
Zack Williamse940c7a2019-08-21 14:25:39 -0700341 case 6: // VLAN_ID
342 f.Set(FLOW_FIELD_VLAN_ID)
Scott Baker9173ed82020-05-19 08:30:12 -0700343 vid := basic.GetVlanVid()
344 mask := basic.GetVlanVidMask() // TODO: can this fail?
345 if vid == ReservedTransparentVlan && mask == ReservedTransparentVlan {
Andrea Campanella086629f2020-02-21 14:15:43 +0100346 f.VlanId = "any"
347 } else {
348 f.VlanId = toVlanId(vid)
349 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700350 case 7: // VLAN_PCP
351 f.Set(FLOW_FIELD_VLAN_PCP)
Scott Baker9173ed82020-05-19 08:30:12 -0700352 f.VlanPcp = fmt.Sprintf("%d", basic.GetVlanPcp())
Zack Williamse940c7a2019-08-21 14:25:39 -0700353 case 10: // IP_PROTO
354 f.Set(FLOW_FIELD_IP_PROTO)
Scott Baker9173ed82020-05-19 08:30:12 -0700355 f.IpProto = fmt.Sprintf("%d", basic.GetIpProto())
Zack Williamse940c7a2019-08-21 14:25:39 -0700356 case 15: // UDP_SRC
357 f.Set(FLOW_FIELD_UDP_SRC)
Scott Baker9173ed82020-05-19 08:30:12 -0700358 f.UdpSrc = fmt.Sprintf("%d", basic.GetUdpSrc())
Zack Williamse940c7a2019-08-21 14:25:39 -0700359 case 16: // UDP_DST
360 f.Set(FLOW_FIELD_UDP_DST)
Scott Baker9173ed82020-05-19 08:30:12 -0700361 f.UdpDst = fmt.Sprintf("%d", basic.GetUdpDst())
Zack Williamse940c7a2019-08-21 14:25:39 -0700362 case 38: // TUNNEL_ID
363 f.Set(FLOW_FIELD_TUNNEL_ID)
Scott Baker9173ed82020-05-19 08:30:12 -0700364 f.TunnelId = fmt.Sprintf("%d", basic.GetTunnelId())
Zack Williamse940c7a2019-08-21 14:25:39 -0700365 default:
366 /*
367 * For unsupported match types put them into an
368 * "Unsupported field so the table/json still
369 * outputs relatively correctly as opposed to
370 * having log messages.
371 */
372 f.Set(FLOW_FIELD_UNSUPPORTED_MATCH)
Scott Baker9173ed82020-05-19 08:30:12 -0700373 f.UnsupportedMatch = appendInt32(f.UnsupportedMatch, int32(basic.Type))
Zack Williamse940c7a2019-08-21 14:25:39 -0700374 }
375 }
Scott Baker9173ed82020-05-19 08:30:12 -0700376 for _, inst := range flow.Instructions {
377 switch inst.Type {
Zack Williamse940c7a2019-08-21 14:25:39 -0700378 case 1: // GOTO_TABLE
379 f.Set(FLOW_FIELD_GOTO_TABLE)
Scott Baker9173ed82020-05-19 08:30:12 -0700380 goto_table := inst.GetGotoTable()
381 f.GotoTable = fmt.Sprintf("%d", goto_table.TableId)
David Bainbridge09c61672019-08-23 19:07:54 +0000382 case 2: // WRITE_METADATA
383 f.Set(FLOW_FIELD_WRITE_METADATA)
Scott Baker9173ed82020-05-19 08:30:12 -0700384 meta := inst.GetWriteMetadata()
385 val := meta.Metadata
386 mask := meta.MetadataMask
David Bainbridge09c61672019-08-23 19:07:54 +0000387 if mask != 0 {
388 f.WriteMetadata = fmt.Sprintf("0x%016x/0x%016x", val, mask)
389 } else {
390 f.WriteMetadata = fmt.Sprintf("0x%016x", val)
391 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700392 case 4: // APPLY_ACTIONS
Scott Baker9173ed82020-05-19 08:30:12 -0700393 for _, action := range inst.GetActions().Actions {
394 switch action.Type {
Zack Williamse940c7a2019-08-21 14:25:39 -0700395 case 0: // OUTPUT
396 f.Set(FLOW_FIELD_OUTPUT)
Scott Baker9173ed82020-05-19 08:30:12 -0700397 output := action.GetOutput()
398 out := output.Port
Zack Williamse940c7a2019-08-21 14:25:39 -0700399 switch out & 0x7fffffff {
400 case 0:
401 f.Output = "INVALID"
402 case 0x7ffffff8:
403 f.Output = "IN_PORT"
404 case 0x7ffffff9:
405 f.Output = "TABLE"
406 case 0x7ffffffa:
407 f.Output = "NORMAL"
408 case 0x7ffffffb:
409 f.Output = "FLOOD"
410 case 0x7ffffffc:
411 f.Output = "ALL"
412 case 0x7ffffffd:
413 f.Output = "CONTROLLER"
414 case 0x7ffffffe:
415 f.Output = "LOCAL"
416 case 0x7fffffff:
417 f.Output = "ANY"
418 default:
Scott Baker9173ed82020-05-19 08:30:12 -0700419 f.Output = fmt.Sprintf("%d", output.Port)
Zack Williamse940c7a2019-08-21 14:25:39 -0700420 }
421 case 17: // PUSH_VLAN
422 f.Set(FLOW_FIELD_PUSH_VLAN_ID)
Scott Baker9173ed82020-05-19 08:30:12 -0700423 push := action.GetPush()
424 f.PushVlanId = fmt.Sprintf("0x%x", push.Ethertype)
Zack Williamse940c7a2019-08-21 14:25:39 -0700425 case 18: // POP_VLAN
426 f.Set(FLOW_FIELD_POP_VLAN)
427 f.PopVlan = "yes"
428 case 25: // SET_FIELD
Scott Baker9173ed82020-05-19 08:30:12 -0700429 set := action.GetSetField().Field
Zack Williamse940c7a2019-08-21 14:25:39 -0700430
431 // Only support OFPXMC_OPENFLOW_BASIC (0x8000)
Scott Baker9173ed82020-05-19 08:30:12 -0700432 if set.OxmClass != 0x8000 {
Zack Williamse940c7a2019-08-21 14:25:39 -0700433 continue
434 }
Scott Baker9173ed82020-05-19 08:30:12 -0700435 basic := set.GetOfbField()
Zack Williamse940c7a2019-08-21 14:25:39 -0700436
Scott Baker9173ed82020-05-19 08:30:12 -0700437 switch basic.Type {
Zack Williamse940c7a2019-08-21 14:25:39 -0700438 case 6: // VLAN_ID
439 f.Set(FLOW_FIELD_SET_VLAN_ID)
Scott Baker9173ed82020-05-19 08:30:12 -0700440 f.SetVlanId = toVlanId(basic.GetVlanVid())
Zack Williamse940c7a2019-08-21 14:25:39 -0700441 default: // Unsupported
442 /*
443 * For unsupported match types put them into an
444 * "Unsupported field so the table/json still
445 * outputs relatively correctly as opposed to
446 * having log messages.
447 */
448 f.Set(FLOW_FIELD_UNSUPPORTED_SET_FIELD)
449 f.UnsupportedSetField = appendInt32(f.UnsupportedSetField,
Scott Baker9173ed82020-05-19 08:30:12 -0700450 int32(basic.Type))
Zack Williamse940c7a2019-08-21 14:25:39 -0700451 }
452 default: // Unsupported
453 /*
454 * For unsupported match types put them into an
455 * "Unsupported field so the table/json still
456 * outputs relatively correctly as opposed to
457 * having log messages.
458 */
459 f.Set(FLOW_FIELD_UNSUPPORTED_ACTION)
460 f.UnsupportedAction = appendInt32(f.UnsupportedAction,
Scott Baker9173ed82020-05-19 08:30:12 -0700461 int32(action.Type))
Zack Williamse940c7a2019-08-21 14:25:39 -0700462 }
463 }
464 case 5: // CLEAR_ACTIONS
465 // Following current CLI, just assigning empty list
466 f.Set(FLOW_FIELD_CLEAR_ACTIONS)
467 f.ClearActions = "[]"
David Bainbridge09c61672019-08-23 19:07:54 +0000468 case 6: // METER
Scott Baker9173ed82020-05-19 08:30:12 -0700469 meter := inst.GetMeter()
David Bainbridge09c61672019-08-23 19:07:54 +0000470 f.Set(FLOW_FIELD_METER)
Scott Baker9173ed82020-05-19 08:30:12 -0700471 f.MeterId = fmt.Sprintf("%d", meter.MeterId)
Zack Williamse940c7a2019-08-21 14:25:39 -0700472 default: // Unsupported
473 /*
474 * For unsupported match types put them into an
475 * "Unsupported field so the table/json still
476 * outputs relatively correctly as opposed to
477 * having log messages.
478 */
479 f.Set(FLOW_FIELD_UNSUPPORTED_INSTRUCTION)
480 f.UnsupportedInstruction = appendUint32(f.UnsupportedInstruction,
Scott Baker9173ed82020-05-19 08:30:12 -0700481 uint32(inst.Type))
Zack Williamse940c7a2019-08-21 14:25:39 -0700482 }
483 }
484}