blob: 1a5f88be7921aaba0c54dcc8cfb9449c67636dcf [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"
Scott Baker9173ed82020-05-19 08:30:12 -070020 "github.com/opencord/voltha-protos/v3/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
Scott Baker9173ed82020-05-19 08:30:12 -0700297func (f *Flow) PopulateFromProto(flow *openflow_13.OfpFlowStats) {
Zack Williamse940c7a2019-08-21 14:25:39 -0700298
299 f.Reset()
Scott Baker9173ed82020-05-19 08:30:12 -0700300 f.Id = fmt.Sprintf("%016x", flow.Id)
301 f.TableId = flow.TableId
302 f.Priority = flow.Priority
Zack Williamse940c7a2019-08-21 14:25:39 -0700303 // mask the lower 8 for the cookie, why?
Scott Baker9173ed82020-05-19 08:30:12 -0700304 cookie := flow.Cookie
Zack Williamse940c7a2019-08-21 14:25:39 -0700305 if cookie == 0 {
306 f.Cookie = "0"
307 } else {
Scott Baker9173ed82020-05-19 08:30:12 -0700308 f.Cookie = fmt.Sprintf("~%08x", flow.Cookie&0xffffffff)
Zack Williamse940c7a2019-08-21 14:25:39 -0700309 }
Scott Baker9173ed82020-05-19 08:30:12 -0700310 f.DurationSec = flow.DurationSec
311 f.DurationNsec = flow.DurationNsec
312 f.IdleTimeout = flow.IdleTimeout
313 f.HardTimeout = flow.HardTimeout
314 f.PacketCount = flow.PacketCount
315 f.ByteCount = flow.ByteCount
Zack Williamse940c7a2019-08-21 14:25:39 -0700316 f.Set(FLOW_FIELD_HEADER | FLOW_FIELD_STATS)
317
Scott Baker9173ed82020-05-19 08:30:12 -0700318 for _, field := range flow.Match.OxmFields {
Zack Williamse940c7a2019-08-21 14:25:39 -0700319 // Only support OFPXMC_OPENFLOW_BASIC (0x8000)
Scott Baker9173ed82020-05-19 08:30:12 -0700320 if field.OxmClass != 0x8000 {
Zack Williamse940c7a2019-08-21 14:25:39 -0700321 continue
322 }
323
Scott Baker9173ed82020-05-19 08:30:12 -0700324 basic := field.GetOfbField()
325
326 switch basic.Type {
Zack Williamse940c7a2019-08-21 14:25:39 -0700327 case 0: // IN_PORT
328 f.Set(FLOW_FIELD_IN_PORT)
Scott Baker9173ed82020-05-19 08:30:12 -0700329 f.InPort = fmt.Sprintf("%d", basic.GetPort())
Zack Williamse940c7a2019-08-21 14:25:39 -0700330 case 2: // METADATA
331 f.Set(FLOW_FIELD_METADATA)
Scott Baker9173ed82020-05-19 08:30:12 -0700332 f.Metadata = fmt.Sprintf("0x%016x", basic.GetTableMetadata())
Zack Williamse940c7a2019-08-21 14:25:39 -0700333 case 5: // ETH_TYPE
334 f.Set(FLOW_FIELD_ETH_TYPE)
Scott Baker9173ed82020-05-19 08:30:12 -0700335 f.EthType = fmt.Sprintf("0x%04x", basic.GetEthType())
Zack Williamse940c7a2019-08-21 14:25:39 -0700336 case 6: // VLAN_ID
337 f.Set(FLOW_FIELD_VLAN_ID)
Scott Baker9173ed82020-05-19 08:30:12 -0700338 vid := basic.GetVlanVid()
339 mask := basic.GetVlanVidMask() // TODO: can this fail?
340 if vid == ReservedTransparentVlan && mask == ReservedTransparentVlan {
Andrea Campanella086629f2020-02-21 14:15:43 +0100341 f.VlanId = "any"
342 } else {
343 f.VlanId = toVlanId(vid)
344 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700345 case 7: // VLAN_PCP
346 f.Set(FLOW_FIELD_VLAN_PCP)
Scott Baker9173ed82020-05-19 08:30:12 -0700347 f.VlanPcp = fmt.Sprintf("%d", basic.GetVlanPcp())
Zack Williamse940c7a2019-08-21 14:25:39 -0700348 case 10: // IP_PROTO
349 f.Set(FLOW_FIELD_IP_PROTO)
Scott Baker9173ed82020-05-19 08:30:12 -0700350 f.IpProto = fmt.Sprintf("%d", basic.GetIpProto())
Zack Williamse940c7a2019-08-21 14:25:39 -0700351 case 15: // UDP_SRC
352 f.Set(FLOW_FIELD_UDP_SRC)
Scott Baker9173ed82020-05-19 08:30:12 -0700353 f.UdpSrc = fmt.Sprintf("%d", basic.GetUdpSrc())
Zack Williamse940c7a2019-08-21 14:25:39 -0700354 case 16: // UDP_DST
355 f.Set(FLOW_FIELD_UDP_DST)
Scott Baker9173ed82020-05-19 08:30:12 -0700356 f.UdpDst = fmt.Sprintf("%d", basic.GetUdpDst())
Zack Williamse940c7a2019-08-21 14:25:39 -0700357 case 38: // TUNNEL_ID
358 f.Set(FLOW_FIELD_TUNNEL_ID)
Scott Baker9173ed82020-05-19 08:30:12 -0700359 f.TunnelId = fmt.Sprintf("%d", basic.GetTunnelId())
Zack Williamse940c7a2019-08-21 14:25:39 -0700360 default:
361 /*
362 * For unsupported match types put them into an
363 * "Unsupported field so the table/json still
364 * outputs relatively correctly as opposed to
365 * having log messages.
366 */
367 f.Set(FLOW_FIELD_UNSUPPORTED_MATCH)
Scott Baker9173ed82020-05-19 08:30:12 -0700368 f.UnsupportedMatch = appendInt32(f.UnsupportedMatch, int32(basic.Type))
Zack Williamse940c7a2019-08-21 14:25:39 -0700369 }
370 }
Scott Baker9173ed82020-05-19 08:30:12 -0700371 for _, inst := range flow.Instructions {
372 switch inst.Type {
Zack Williamse940c7a2019-08-21 14:25:39 -0700373 case 1: // GOTO_TABLE
374 f.Set(FLOW_FIELD_GOTO_TABLE)
Scott Baker9173ed82020-05-19 08:30:12 -0700375 goto_table := inst.GetGotoTable()
376 f.GotoTable = fmt.Sprintf("%d", goto_table.TableId)
David Bainbridge09c61672019-08-23 19:07:54 +0000377 case 2: // WRITE_METADATA
378 f.Set(FLOW_FIELD_WRITE_METADATA)
Scott Baker9173ed82020-05-19 08:30:12 -0700379 meta := inst.GetWriteMetadata()
380 val := meta.Metadata
381 mask := meta.MetadataMask
David Bainbridge09c61672019-08-23 19:07:54 +0000382 if mask != 0 {
383 f.WriteMetadata = fmt.Sprintf("0x%016x/0x%016x", val, mask)
384 } else {
385 f.WriteMetadata = fmt.Sprintf("0x%016x", val)
386 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700387 case 4: // APPLY_ACTIONS
Scott Baker9173ed82020-05-19 08:30:12 -0700388 for _, action := range inst.GetActions().Actions {
389 switch action.Type {
Zack Williamse940c7a2019-08-21 14:25:39 -0700390 case 0: // OUTPUT
391 f.Set(FLOW_FIELD_OUTPUT)
Scott Baker9173ed82020-05-19 08:30:12 -0700392 output := action.GetOutput()
393 out := output.Port
Zack Williamse940c7a2019-08-21 14:25:39 -0700394 switch out & 0x7fffffff {
395 case 0:
396 f.Output = "INVALID"
397 case 0x7ffffff8:
398 f.Output = "IN_PORT"
399 case 0x7ffffff9:
400 f.Output = "TABLE"
401 case 0x7ffffffa:
402 f.Output = "NORMAL"
403 case 0x7ffffffb:
404 f.Output = "FLOOD"
405 case 0x7ffffffc:
406 f.Output = "ALL"
407 case 0x7ffffffd:
408 f.Output = "CONTROLLER"
409 case 0x7ffffffe:
410 f.Output = "LOCAL"
411 case 0x7fffffff:
412 f.Output = "ANY"
413 default:
Scott Baker9173ed82020-05-19 08:30:12 -0700414 f.Output = fmt.Sprintf("%d", output.Port)
Zack Williamse940c7a2019-08-21 14:25:39 -0700415 }
416 case 17: // PUSH_VLAN
417 f.Set(FLOW_FIELD_PUSH_VLAN_ID)
Scott Baker9173ed82020-05-19 08:30:12 -0700418 push := action.GetPush()
419 f.PushVlanId = fmt.Sprintf("0x%x", push.Ethertype)
Zack Williamse940c7a2019-08-21 14:25:39 -0700420 case 18: // POP_VLAN
421 f.Set(FLOW_FIELD_POP_VLAN)
422 f.PopVlan = "yes"
423 case 25: // SET_FIELD
Scott Baker9173ed82020-05-19 08:30:12 -0700424 set := action.GetSetField().Field
Zack Williamse940c7a2019-08-21 14:25:39 -0700425
426 // Only support OFPXMC_OPENFLOW_BASIC (0x8000)
Scott Baker9173ed82020-05-19 08:30:12 -0700427 if set.OxmClass != 0x8000 {
Zack Williamse940c7a2019-08-21 14:25:39 -0700428 continue
429 }
Scott Baker9173ed82020-05-19 08:30:12 -0700430 basic := set.GetOfbField()
Zack Williamse940c7a2019-08-21 14:25:39 -0700431
Scott Baker9173ed82020-05-19 08:30:12 -0700432 switch basic.Type {
Zack Williamse940c7a2019-08-21 14:25:39 -0700433 case 6: // VLAN_ID
434 f.Set(FLOW_FIELD_SET_VLAN_ID)
Scott Baker9173ed82020-05-19 08:30:12 -0700435 f.SetVlanId = toVlanId(basic.GetVlanVid())
Zack Williamse940c7a2019-08-21 14:25:39 -0700436 default: // Unsupported
437 /*
438 * For unsupported match types put them into an
439 * "Unsupported field so the table/json still
440 * outputs relatively correctly as opposed to
441 * having log messages.
442 */
443 f.Set(FLOW_FIELD_UNSUPPORTED_SET_FIELD)
444 f.UnsupportedSetField = appendInt32(f.UnsupportedSetField,
Scott Baker9173ed82020-05-19 08:30:12 -0700445 int32(basic.Type))
Zack Williamse940c7a2019-08-21 14:25:39 -0700446 }
447 default: // Unsupported
448 /*
449 * For unsupported match types put them into an
450 * "Unsupported field so the table/json still
451 * outputs relatively correctly as opposed to
452 * having log messages.
453 */
454 f.Set(FLOW_FIELD_UNSUPPORTED_ACTION)
455 f.UnsupportedAction = appendInt32(f.UnsupportedAction,
Scott Baker9173ed82020-05-19 08:30:12 -0700456 int32(action.Type))
Zack Williamse940c7a2019-08-21 14:25:39 -0700457 }
458 }
459 case 5: // CLEAR_ACTIONS
460 // Following current CLI, just assigning empty list
461 f.Set(FLOW_FIELD_CLEAR_ACTIONS)
462 f.ClearActions = "[]"
David Bainbridge09c61672019-08-23 19:07:54 +0000463 case 6: // METER
Scott Baker9173ed82020-05-19 08:30:12 -0700464 meter := inst.GetMeter()
David Bainbridge09c61672019-08-23 19:07:54 +0000465 f.Set(FLOW_FIELD_METER)
Scott Baker9173ed82020-05-19 08:30:12 -0700466 f.MeterId = fmt.Sprintf("%d", meter.MeterId)
Zack Williamse940c7a2019-08-21 14:25:39 -0700467 default: // Unsupported
468 /*
469 * For unsupported match types put them into an
470 * "Unsupported field so the table/json still
471 * outputs relatively correctly as opposed to
472 * having log messages.
473 */
474 f.Set(FLOW_FIELD_UNSUPPORTED_INSTRUCTION)
475 f.UnsupportedInstruction = appendUint32(f.UnsupportedInstruction,
Scott Baker9173ed82020-05-19 08:30:12 -0700476 uint32(inst.Type))
Zack Williamse940c7a2019-08-21 14:25:39 -0700477 }
478 }
479}