blob: 3139144221034d3cc285ac8433e30266b96d33ef [file] [log] [blame]
Scott Baker456b8932019-10-24 10:36:39 -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 */
16package flows
17
18import (
19 "bytes"
20 "crypto/md5"
Kent Hagermanf9cbe692020-05-05 17:50:26 -040021 "encoding/binary"
Scott Baker456b8932019-10-24 10:36:39 -070022 "fmt"
Kent Hagermanf9cbe692020-05-05 17:50:26 -040023 "hash"
24 "sort"
25
Scott Baker456b8932019-10-24 10:36:39 -070026 "github.com/cevaris/ordered_map"
27 "github.com/gogo/protobuf/proto"
serkant.uluderyab38671c2019-11-01 09:35:38 -070028 "github.com/opencord/voltha-lib-go/v3/pkg/log"
29 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
Scott Baker456b8932019-10-24 10:36:39 -070030)
31
32var (
33 // Instructions shortcut
34 APPLY_ACTIONS = ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS
35 WRITE_METADATA = ofp.OfpInstructionType_OFPIT_WRITE_METADATA
36 METER_ACTION = ofp.OfpInstructionType_OFPIT_METER
37
38 //OFPAT_* shortcuts
39 OUTPUT = ofp.OfpActionType_OFPAT_OUTPUT
40 COPY_TTL_OUT = ofp.OfpActionType_OFPAT_COPY_TTL_OUT
41 COPY_TTL_IN = ofp.OfpActionType_OFPAT_COPY_TTL_IN
42 SET_MPLS_TTL = ofp.OfpActionType_OFPAT_SET_MPLS_TTL
43 DEC_MPLS_TTL = ofp.OfpActionType_OFPAT_DEC_MPLS_TTL
44 PUSH_VLAN = ofp.OfpActionType_OFPAT_PUSH_VLAN
45 POP_VLAN = ofp.OfpActionType_OFPAT_POP_VLAN
46 PUSH_MPLS = ofp.OfpActionType_OFPAT_PUSH_MPLS
47 POP_MPLS = ofp.OfpActionType_OFPAT_POP_MPLS
48 SET_QUEUE = ofp.OfpActionType_OFPAT_SET_QUEUE
49 GROUP = ofp.OfpActionType_OFPAT_GROUP
50 SET_NW_TTL = ofp.OfpActionType_OFPAT_SET_NW_TTL
51 NW_TTL = ofp.OfpActionType_OFPAT_DEC_NW_TTL
52 SET_FIELD = ofp.OfpActionType_OFPAT_SET_FIELD
53 PUSH_PBB = ofp.OfpActionType_OFPAT_PUSH_PBB
54 POP_PBB = ofp.OfpActionType_OFPAT_POP_PBB
55 EXPERIMENTER = ofp.OfpActionType_OFPAT_EXPERIMENTER
56
57 //OFPXMT_OFB_* shortcuts (incomplete)
58 IN_PORT = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT
59 IN_PHY_PORT = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT
60 METADATA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_METADATA
61 ETH_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_DST
62 ETH_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_SRC
63 ETH_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE
64 VLAN_VID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID
65 VLAN_PCP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP
66 IP_DSCP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_DSCP
67 IP_ECN = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_ECN
68 IP_PROTO = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO
69 IPV4_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_SRC
70 IPV4_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST
71 TCP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TCP_SRC
72 TCP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TCP_DST
73 UDP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC
74 UDP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST
75 SCTP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_SCTP_SRC
76 SCTP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_SCTP_DST
77 ICMPV4_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV4_TYPE
78 ICMPV4_CODE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV4_CODE
79 ARP_OP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_OP
80 ARP_SPA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_SPA
81 ARP_TPA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_TPA
82 ARP_SHA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_SHA
83 ARP_THA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_THA
84 IPV6_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_SRC
85 IPV6_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_DST
86 IPV6_FLABEL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_FLABEL
87 ICMPV6_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV6_TYPE
88 ICMPV6_CODE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV6_CODE
89 IPV6_ND_TARGET = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_TARGET
90 OFB_IPV6_ND_SLL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_SLL
91 IPV6_ND_TLL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_TLL
92 MPLS_LABEL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_LABEL
93 MPLS_TC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_TC
94 MPLS_BOS = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_BOS
95 PBB_ISID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_PBB_ISID
96 TUNNEL_ID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TUNNEL_ID
97 IPV6_EXTHDR = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_EXTHDR
98)
99
100//ofp_action_* shortcuts
101
102func Output(port uint32, maxLen ...ofp.OfpControllerMaxLen) *ofp.OfpAction {
103 maxLength := ofp.OfpControllerMaxLen_OFPCML_MAX
104 if len(maxLen) > 0 {
105 maxLength = maxLen[0]
106 }
107 return &ofp.OfpAction{Type: OUTPUT, Action: &ofp.OfpAction_Output{Output: &ofp.OfpActionOutput{Port: port, MaxLen: uint32(maxLength)}}}
108}
109
110func MplsTtl(ttl uint32) *ofp.OfpAction {
111 return &ofp.OfpAction{Type: SET_MPLS_TTL, Action: &ofp.OfpAction_MplsTtl{MplsTtl: &ofp.OfpActionMplsTtl{MplsTtl: ttl}}}
112}
113
114func PushVlan(ethType uint32) *ofp.OfpAction {
115 return &ofp.OfpAction{Type: PUSH_VLAN, Action: &ofp.OfpAction_Push{Push: &ofp.OfpActionPush{Ethertype: ethType}}}
116}
117
118func PopVlan() *ofp.OfpAction {
119 return &ofp.OfpAction{Type: POP_VLAN}
120}
121
122func PopMpls(ethType uint32) *ofp.OfpAction {
123 return &ofp.OfpAction{Type: POP_MPLS, Action: &ofp.OfpAction_PopMpls{PopMpls: &ofp.OfpActionPopMpls{Ethertype: ethType}}}
124}
125
126func Group(groupId uint32) *ofp.OfpAction {
127 return &ofp.OfpAction{Type: GROUP, Action: &ofp.OfpAction_Group{Group: &ofp.OfpActionGroup{GroupId: groupId}}}
128}
129
130func NwTtl(nwTtl uint32) *ofp.OfpAction {
131 return &ofp.OfpAction{Type: NW_TTL, Action: &ofp.OfpAction_NwTtl{NwTtl: &ofp.OfpActionNwTtl{NwTtl: nwTtl}}}
132}
133
134func SetField(field *ofp.OfpOxmOfbField) *ofp.OfpAction {
135 actionSetField := &ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: &ofp.OfpOxmField_OfbField{OfbField: field}}
136 return &ofp.OfpAction{Type: SET_FIELD, Action: &ofp.OfpAction_SetField{SetField: &ofp.OfpActionSetField{Field: actionSetField}}}
137}
138
139func Experimenter(experimenter uint32, data []byte) *ofp.OfpAction {
140 return &ofp.OfpAction{Type: EXPERIMENTER, Action: &ofp.OfpAction_Experimenter{Experimenter: &ofp.OfpActionExperimenter{Experimenter: experimenter, Data: data}}}
141}
142
143//ofb_field generators (incomplete set)
144
145func InPort(inPort uint32) *ofp.OfpOxmOfbField {
146 return &ofp.OfpOxmOfbField{Type: IN_PORT, Value: &ofp.OfpOxmOfbField_Port{Port: inPort}}
147}
148
149func InPhyPort(inPhyPort uint32) *ofp.OfpOxmOfbField {
150 return &ofp.OfpOxmOfbField{Type: IN_PHY_PORT, Value: &ofp.OfpOxmOfbField_Port{Port: inPhyPort}}
151}
152
153func Metadata_ofp(tableMetadata uint64) *ofp.OfpOxmOfbField {
154 return &ofp.OfpOxmOfbField{Type: METADATA, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: tableMetadata}}
155}
156
157// should Metadata_ofp used here ?????
158func EthDst(ethDst uint64) *ofp.OfpOxmOfbField {
159 return &ofp.OfpOxmOfbField{Type: ETH_DST, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: ethDst}}
160}
161
162// should Metadata_ofp used here ?????
163func EthSrc(ethSrc uint64) *ofp.OfpOxmOfbField {
164 return &ofp.OfpOxmOfbField{Type: ETH_SRC, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: ethSrc}}
165}
166
167func EthType(ethType uint32) *ofp.OfpOxmOfbField {
168 return &ofp.OfpOxmOfbField{Type: ETH_TYPE, Value: &ofp.OfpOxmOfbField_EthType{EthType: ethType}}
169}
170
171func VlanVid(vlanVid uint32) *ofp.OfpOxmOfbField {
172 return &ofp.OfpOxmOfbField{Type: VLAN_VID, Value: &ofp.OfpOxmOfbField_VlanVid{VlanVid: vlanVid}}
173}
174
175func VlanPcp(vlanPcp uint32) *ofp.OfpOxmOfbField {
176 return &ofp.OfpOxmOfbField{Type: VLAN_PCP, Value: &ofp.OfpOxmOfbField_VlanPcp{VlanPcp: vlanPcp}}
177}
178
179func IpDscp(ipDscp uint32) *ofp.OfpOxmOfbField {
180 return &ofp.OfpOxmOfbField{Type: IP_DSCP, Value: &ofp.OfpOxmOfbField_IpDscp{IpDscp: ipDscp}}
181}
182
183func IpEcn(ipEcn uint32) *ofp.OfpOxmOfbField {
184 return &ofp.OfpOxmOfbField{Type: IP_ECN, Value: &ofp.OfpOxmOfbField_IpEcn{IpEcn: ipEcn}}
185}
186
187func IpProto(ipProto uint32) *ofp.OfpOxmOfbField {
188 return &ofp.OfpOxmOfbField{Type: IP_PROTO, Value: &ofp.OfpOxmOfbField_IpProto{IpProto: ipProto}}
189}
190
191func Ipv4Src(ipv4Src uint32) *ofp.OfpOxmOfbField {
192 return &ofp.OfpOxmOfbField{Type: IPV4_SRC, Value: &ofp.OfpOxmOfbField_Ipv4Src{Ipv4Src: ipv4Src}}
193}
194
195func Ipv4Dst(ipv4Dst uint32) *ofp.OfpOxmOfbField {
196 return &ofp.OfpOxmOfbField{Type: IPV4_DST, Value: &ofp.OfpOxmOfbField_Ipv4Dst{Ipv4Dst: ipv4Dst}}
197}
198
199func TcpSrc(tcpSrc uint32) *ofp.OfpOxmOfbField {
200 return &ofp.OfpOxmOfbField{Type: TCP_SRC, Value: &ofp.OfpOxmOfbField_TcpSrc{TcpSrc: tcpSrc}}
201}
202
203func TcpDst(tcpDst uint32) *ofp.OfpOxmOfbField {
204 return &ofp.OfpOxmOfbField{Type: TCP_DST, Value: &ofp.OfpOxmOfbField_TcpDst{TcpDst: tcpDst}}
205}
206
207func UdpSrc(udpSrc uint32) *ofp.OfpOxmOfbField {
208 return &ofp.OfpOxmOfbField{Type: UDP_SRC, Value: &ofp.OfpOxmOfbField_UdpSrc{UdpSrc: udpSrc}}
209}
210
211func UdpDst(udpDst uint32) *ofp.OfpOxmOfbField {
212 return &ofp.OfpOxmOfbField{Type: UDP_DST, Value: &ofp.OfpOxmOfbField_UdpDst{UdpDst: udpDst}}
213}
214
215func SctpSrc(sctpSrc uint32) *ofp.OfpOxmOfbField {
216 return &ofp.OfpOxmOfbField{Type: SCTP_SRC, Value: &ofp.OfpOxmOfbField_SctpSrc{SctpSrc: sctpSrc}}
217}
218
219func SctpDst(sctpDst uint32) *ofp.OfpOxmOfbField {
220 return &ofp.OfpOxmOfbField{Type: SCTP_DST, Value: &ofp.OfpOxmOfbField_SctpDst{SctpDst: sctpDst}}
221}
222
223func Icmpv4Type(icmpv4Type uint32) *ofp.OfpOxmOfbField {
224 return &ofp.OfpOxmOfbField{Type: ICMPV4_TYPE, Value: &ofp.OfpOxmOfbField_Icmpv4Type{Icmpv4Type: icmpv4Type}}
225}
226
227func Icmpv4Code(icmpv4Code uint32) *ofp.OfpOxmOfbField {
228 return &ofp.OfpOxmOfbField{Type: ICMPV4_CODE, Value: &ofp.OfpOxmOfbField_Icmpv4Code{Icmpv4Code: icmpv4Code}}
229}
230
231func ArpOp(arpOp uint32) *ofp.OfpOxmOfbField {
232 return &ofp.OfpOxmOfbField{Type: ARP_OP, Value: &ofp.OfpOxmOfbField_ArpOp{ArpOp: arpOp}}
233}
234
235func ArpSpa(arpSpa uint32) *ofp.OfpOxmOfbField {
236 return &ofp.OfpOxmOfbField{Type: ARP_SPA, Value: &ofp.OfpOxmOfbField_ArpSpa{ArpSpa: arpSpa}}
237}
238
239func ArpTpa(arpTpa uint32) *ofp.OfpOxmOfbField {
240 return &ofp.OfpOxmOfbField{Type: ARP_TPA, Value: &ofp.OfpOxmOfbField_ArpTpa{ArpTpa: arpTpa}}
241}
242
243func ArpSha(arpSha []byte) *ofp.OfpOxmOfbField {
244 return &ofp.OfpOxmOfbField{Type: ARP_SHA, Value: &ofp.OfpOxmOfbField_ArpSha{ArpSha: arpSha}}
245}
246
247func ArpTha(arpTha []byte) *ofp.OfpOxmOfbField {
248 return &ofp.OfpOxmOfbField{Type: ARP_THA, Value: &ofp.OfpOxmOfbField_ArpTha{ArpTha: arpTha}}
249}
250
251func Ipv6Src(ipv6Src []byte) *ofp.OfpOxmOfbField {
252 return &ofp.OfpOxmOfbField{Type: IPV6_SRC, Value: &ofp.OfpOxmOfbField_Ipv6Src{Ipv6Src: ipv6Src}}
253}
254
255func Ipv6Dst(ipv6Dst []byte) *ofp.OfpOxmOfbField {
256 return &ofp.OfpOxmOfbField{Type: IPV6_DST, Value: &ofp.OfpOxmOfbField_Ipv6Dst{Ipv6Dst: ipv6Dst}}
257}
258
259func Ipv6Flabel(ipv6Flabel uint32) *ofp.OfpOxmOfbField {
260 return &ofp.OfpOxmOfbField{Type: IPV6_FLABEL, Value: &ofp.OfpOxmOfbField_Ipv6Flabel{Ipv6Flabel: ipv6Flabel}}
261}
262
263func Icmpv6Type(icmpv6Type uint32) *ofp.OfpOxmOfbField {
264 return &ofp.OfpOxmOfbField{Type: ICMPV6_TYPE, Value: &ofp.OfpOxmOfbField_Icmpv6Type{Icmpv6Type: icmpv6Type}}
265}
266
267func Icmpv6Code(icmpv6Code uint32) *ofp.OfpOxmOfbField {
268 return &ofp.OfpOxmOfbField{Type: ICMPV6_CODE, Value: &ofp.OfpOxmOfbField_Icmpv6Code{Icmpv6Code: icmpv6Code}}
269}
270
271func Ipv6NdTarget(ipv6NdTarget []byte) *ofp.OfpOxmOfbField {
272 return &ofp.OfpOxmOfbField{Type: IPV6_ND_TARGET, Value: &ofp.OfpOxmOfbField_Ipv6NdTarget{Ipv6NdTarget: ipv6NdTarget}}
273}
274
275func OfbIpv6NdSll(ofbIpv6NdSll []byte) *ofp.OfpOxmOfbField {
276 return &ofp.OfpOxmOfbField{Type: OFB_IPV6_ND_SLL, Value: &ofp.OfpOxmOfbField_Ipv6NdSsl{Ipv6NdSsl: ofbIpv6NdSll}}
277}
278
279func Ipv6NdTll(ipv6NdTll []byte) *ofp.OfpOxmOfbField {
280 return &ofp.OfpOxmOfbField{Type: IPV6_ND_TLL, Value: &ofp.OfpOxmOfbField_Ipv6NdTll{Ipv6NdTll: ipv6NdTll}}
281}
282
283func MplsLabel(mplsLabel uint32) *ofp.OfpOxmOfbField {
284 return &ofp.OfpOxmOfbField{Type: MPLS_LABEL, Value: &ofp.OfpOxmOfbField_MplsLabel{MplsLabel: mplsLabel}}
285}
286
287func MplsTc(mplsTc uint32) *ofp.OfpOxmOfbField {
288 return &ofp.OfpOxmOfbField{Type: MPLS_TC, Value: &ofp.OfpOxmOfbField_MplsTc{MplsTc: mplsTc}}
289}
290
291func MplsBos(mplsBos uint32) *ofp.OfpOxmOfbField {
292 return &ofp.OfpOxmOfbField{Type: MPLS_BOS, Value: &ofp.OfpOxmOfbField_MplsBos{MplsBos: mplsBos}}
293}
294
295func PbbIsid(pbbIsid uint32) *ofp.OfpOxmOfbField {
296 return &ofp.OfpOxmOfbField{Type: PBB_ISID, Value: &ofp.OfpOxmOfbField_PbbIsid{PbbIsid: pbbIsid}}
297}
298
299func TunnelId(tunnelId uint64) *ofp.OfpOxmOfbField {
300 return &ofp.OfpOxmOfbField{Type: TUNNEL_ID, Value: &ofp.OfpOxmOfbField_TunnelId{TunnelId: tunnelId}}
301}
302
303func Ipv6Exthdr(ipv6Exthdr uint32) *ofp.OfpOxmOfbField {
304 return &ofp.OfpOxmOfbField{Type: IPV6_EXTHDR, Value: &ofp.OfpOxmOfbField_Ipv6Exthdr{Ipv6Exthdr: ipv6Exthdr}}
305}
306
307//frequently used extractors
308
309func excludeAction(action *ofp.OfpAction, exclude ...ofp.OfpActionType) bool {
310 for _, actionToExclude := range exclude {
311 if action.Type == actionToExclude {
312 return true
313 }
314 }
315 return false
316}
317
318func GetActions(flow *ofp.OfpFlowStats, exclude ...ofp.OfpActionType) []*ofp.OfpAction {
319 if flow == nil {
320 return nil
321 }
322 for _, instruction := range flow.Instructions {
323 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
324 instActions := instruction.GetActions()
325 if instActions == nil {
326 return nil
327 }
328 if len(exclude) == 0 {
329 return instActions.Actions
330 } else {
331 filteredAction := make([]*ofp.OfpAction, 0)
332 for _, action := range instActions.Actions {
333 if !excludeAction(action, exclude...) {
334 filteredAction = append(filteredAction, action)
335 }
336 }
337 return filteredAction
338 }
339 }
340 }
341 return nil
342}
343
344func UpdateOutputPortByActionType(flow *ofp.OfpFlowStats, actionType uint32, toPort uint32) *ofp.OfpFlowStats {
345 if flow == nil {
346 return nil
347 }
348 nFlow := (proto.Clone(flow)).(*ofp.OfpFlowStats)
349 nFlow.Instructions = nil
350 nInsts := make([]*ofp.OfpInstruction, 0)
351 for _, instruction := range flow.Instructions {
352 if instruction.Type == actionType {
353 instActions := instruction.GetActions()
354 if instActions == nil {
355 return nil
356 }
357 nActions := make([]*ofp.OfpAction, 0)
358 for _, action := range instActions.Actions {
359 if action.GetOutput() != nil {
360 nActions = append(nActions, Output(toPort))
361 } else {
362 nActions = append(nActions, action)
363 }
364 }
365 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: nActions}}
366 nInsts = append(nInsts, &ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction})
367 } else {
368 nInsts = append(nInsts, instruction)
369 }
370 }
371 nFlow.Instructions = nInsts
372 return nFlow
373}
374
375func excludeOxmOfbField(field *ofp.OfpOxmOfbField, exclude ...ofp.OxmOfbFieldTypes) bool {
376 for _, fieldToExclude := range exclude {
377 if field.Type == fieldToExclude {
378 return true
379 }
380 }
381 return false
382}
383
384func GetOfbFields(flow *ofp.OfpFlowStats, exclude ...ofp.OxmOfbFieldTypes) []*ofp.OfpOxmOfbField {
385 if flow == nil || flow.Match == nil || flow.Match.Type != ofp.OfpMatchType_OFPMT_OXM {
386 return nil
387 }
388 ofbFields := make([]*ofp.OfpOxmOfbField, 0)
389 for _, field := range flow.Match.OxmFields {
390 if field.OxmClass == ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
391 ofbFields = append(ofbFields, field.GetOfbField())
392 }
393 }
394 if len(exclude) == 0 {
395 return ofbFields
396 } else {
397 filteredFields := make([]*ofp.OfpOxmOfbField, 0)
398 for _, ofbField := range ofbFields {
399 if !excludeOxmOfbField(ofbField, exclude...) {
400 filteredFields = append(filteredFields, ofbField)
401 }
402 }
403 return filteredFields
404 }
405}
406
407func GetPacketOutPort(packet *ofp.OfpPacketOut) uint32 {
408 if packet == nil {
409 return 0
410 }
411 for _, action := range packet.GetActions() {
412 if action.Type == OUTPUT {
413 return action.GetOutput().Port
414 }
415 }
416 return 0
417}
418
419func GetOutPort(flow *ofp.OfpFlowStats) uint32 {
420 if flow == nil {
421 return 0
422 }
423 for _, action := range GetActions(flow) {
424 if action.Type == OUTPUT {
425 out := action.GetOutput()
426 if out == nil {
427 return 0
428 }
429 return out.GetPort()
430 }
431 }
432 return 0
433}
434
435func GetInPort(flow *ofp.OfpFlowStats) uint32 {
436 if flow == nil {
437 return 0
438 }
439 for _, field := range GetOfbFields(flow) {
440 if field.Type == IN_PORT {
441 return field.GetPort()
442 }
443 }
444 return 0
445}
446
447func GetGotoTableId(flow *ofp.OfpFlowStats) uint32 {
448 if flow == nil {
449 return 0
450 }
451 for _, instruction := range flow.Instructions {
452 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE) {
453 gotoTable := instruction.GetGotoTable()
454 if gotoTable == nil {
455 return 0
456 }
457 return gotoTable.GetTableId()
458 }
459 }
460 return 0
461}
462
463func GetMeterId(flow *ofp.OfpFlowStats) uint32 {
464 if flow == nil {
465 return 0
466 }
467 for _, instruction := range flow.Instructions {
468 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_METER) {
469 MeterInstruction := instruction.GetMeter()
470 if MeterInstruction == nil {
471 return 0
472 }
473 return MeterInstruction.GetMeterId()
474 }
475 }
476 return 0
477}
478
479func GetVlanVid(flow *ofp.OfpFlowStats) *uint32 {
480 if flow == nil {
481 return nil
482 }
483 for _, field := range GetOfbFields(flow) {
484 if field.Type == VLAN_VID {
485 ret := field.GetVlanVid()
486 return &ret
487 }
488 }
489 // Dont return 0 if the field is missing as vlan id value 0 has meaning and cannot be overloaded as "not found"
490 return nil
491}
492
493func GetTunnelId(flow *ofp.OfpFlowStats) uint64 {
494 if flow == nil {
495 return 0
496 }
497 for _, field := range GetOfbFields(flow) {
498 if field.Type == TUNNEL_ID {
499 return field.GetTunnelId()
500 }
501 }
502 return 0
503}
504
505//GetMetaData - legacy get method (only want lower 32 bits)
Scott Bakere6685952020-06-23 04:05:39 +0000506func GetMetaData(flow *ofp.OfpFlowStats) uint32 {
Scott Baker456b8932019-10-24 10:36:39 -0700507 if flow == nil {
508 return 0
509 }
510 for _, field := range GetOfbFields(flow) {
511 if field.Type == METADATA {
512 return uint32(field.GetTableMetadata() & 0xFFFFFFFF)
513 }
514 }
Scott Bakere6685952020-06-23 04:05:39 +0000515 logger.Debug("No-metadata-present")
Scott Baker456b8932019-10-24 10:36:39 -0700516 return 0
517}
518
Scott Bakere6685952020-06-23 04:05:39 +0000519func GetMetaData64Bit(flow *ofp.OfpFlowStats) uint64 {
Scott Baker456b8932019-10-24 10:36:39 -0700520 if flow == nil {
521 return 0
522 }
523 for _, field := range GetOfbFields(flow) {
524 if field.Type == METADATA {
525 return field.GetTableMetadata()
526 }
527 }
Scott Bakere6685952020-06-23 04:05:39 +0000528 logger.Debug("No-metadata-present")
Scott Baker456b8932019-10-24 10:36:39 -0700529 return 0
530}
531
532// function returns write metadata value from write_metadata action field
Scott Bakere6685952020-06-23 04:05:39 +0000533func GetMetadataFromWriteMetadataAction(flow *ofp.OfpFlowStats) uint64 {
Scott Baker456b8932019-10-24 10:36:39 -0700534 if flow != nil {
535 for _, instruction := range flow.Instructions {
536 if instruction.Type == uint32(WRITE_METADATA) {
537 if writeMetadata := instruction.GetWriteMetadata(); writeMetadata != nil {
538 return writeMetadata.GetMetadata()
539 }
540 }
541 }
542 }
Scott Bakere6685952020-06-23 04:05:39 +0000543 logger.Debugw("No-write-metadata-present", log.Fields{"flow": flow})
Scott Baker456b8932019-10-24 10:36:39 -0700544 return 0
545}
546
Scott Bakere6685952020-06-23 04:05:39 +0000547func GetTechProfileIDFromWriteMetaData(metadata uint64) uint16 {
Scott Baker456b8932019-10-24 10:36:39 -0700548 /*
549 Write metadata instruction value (metadata) is 8 bytes:
550 MS 2 bytes: C Tag
551 Next 2 bytes: Technology Profile Id
552 Next 4 bytes: Port number (uni or nni)
553
554 This is set in the ONOS OltPipeline as a write metadata instruction
555 */
556 var tpId uint16 = 0
Scott Bakere6685952020-06-23 04:05:39 +0000557 logger.Debugw("Write metadata value for Techprofile ID", log.Fields{"metadata": metadata})
Scott Baker456b8932019-10-24 10:36:39 -0700558 if metadata != 0 {
559 tpId = uint16((metadata >> 32) & 0xFFFF)
Scott Bakere6685952020-06-23 04:05:39 +0000560 logger.Debugw("Found techprofile ID from write metadata action", log.Fields{"tpid": tpId})
Scott Baker456b8932019-10-24 10:36:39 -0700561 }
562 return tpId
563}
564
Scott Bakere6685952020-06-23 04:05:39 +0000565func GetEgressPortNumberFromWriteMetadata(flow *ofp.OfpFlowStats) uint32 {
Scott Baker456b8932019-10-24 10:36:39 -0700566 /*
567 Write metadata instruction value (metadata) is 8 bytes:
568 MS 2 bytes: C Tag
569 Next 2 bytes: Technology Profile Id
570 Next 4 bytes: Port number (uni or nni)
571 This is set in the ONOS OltPipeline as a write metadata instruction
572 */
573 var uniPort uint32 = 0
Scott Bakere6685952020-06-23 04:05:39 +0000574 md := GetMetadataFromWriteMetadataAction(flow)
575 logger.Debugw("Metadata found for egress/uni port ", log.Fields{"metadata": md})
Scott Baker456b8932019-10-24 10:36:39 -0700576 if md != 0 {
577 uniPort = uint32(md & 0xFFFFFFFF)
Scott Bakere6685952020-06-23 04:05:39 +0000578 logger.Debugw("Found EgressPort from write metadata action", log.Fields{"egress_port": uniPort})
Scott Baker456b8932019-10-24 10:36:39 -0700579 }
580 return uniPort
581
582}
583
Scott Bakere6685952020-06-23 04:05:39 +0000584func GetInnerTagFromMetaData(flow *ofp.OfpFlowStats) uint16 {
Scott Baker456b8932019-10-24 10:36:39 -0700585 /*
586 Write metadata instruction value (metadata) is 8 bytes:
587 MS 2 bytes: C Tag
588 Next 2 bytes: Technology Profile Id
589 Next 4 bytes: Port number (uni or nni)
590 This is set in the ONOS OltPipeline as a write metadata instruction
591 */
592 var innerTag uint16 = 0
Scott Bakere6685952020-06-23 04:05:39 +0000593 md := GetMetadataFromWriteMetadataAction(flow)
Scott Baker456b8932019-10-24 10:36:39 -0700594 if md != 0 {
595 innerTag = uint16((md >> 48) & 0xFFFF)
Scott Bakere6685952020-06-23 04:05:39 +0000596 logger.Debugw("Found CVLAN from write metadate action", log.Fields{"c_vlan": innerTag})
Scott Baker456b8932019-10-24 10:36:39 -0700597 }
598 return innerTag
599}
600
601//GetInnerTagFromMetaData retrieves the inner tag from the Metadata_ofp. The port number (UNI on ONU) is in the
602// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
603//// a Metadata_ofp field
604/*func GetInnerTagFromMetaData(flow *ofp.OfpFlowStats) uint64 {
605 md := GetMetaData64Bit(flow)
606 if md == 0 {
607 return 0
608 }
609 if md <= 0xffffffff {
Scott Bakere6685952020-06-23 04:05:39 +0000610 logger.Debugw("onos-upgrade-suggested", logger.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
Scott Baker456b8932019-10-24 10:36:39 -0700611 return md
612 }
613 return (md >> 32) & 0xffffffff
614}*/
615
616// Extract the child device port from a flow that contains the parent device peer port. Typically the UNI port of an
617// ONU child device. Per TST agreement this will be the lower 32 bits of tunnel id reserving upper 32 bits for later
618// use
619func GetChildPortFromTunnelId(flow *ofp.OfpFlowStats) uint32 {
620 tid := GetTunnelId(flow)
621 if tid == 0 {
622 return 0
623 }
624 // Per TST agreement we are keeping any child port id (uni port id) in the lower 32 bits
625 return uint32(tid & 0xffffffff)
626}
627
628func HasNextTable(flow *ofp.OfpFlowStats) bool {
629 if flow == nil {
630 return false
631 }
632 return GetGotoTableId(flow) != 0
633}
634
635func GetGroup(flow *ofp.OfpFlowStats) uint32 {
636 if flow == nil {
637 return 0
638 }
639 for _, action := range GetActions(flow) {
640 if action.Type == GROUP {
641 grp := action.GetGroup()
642 if grp == nil {
643 return 0
644 }
645 return grp.GetGroupId()
646 }
647 }
648 return 0
649}
650
651func HasGroup(flow *ofp.OfpFlowStats) bool {
652 return GetGroup(flow) != 0
653}
654
655// GetNextTableId returns the next table ID if the "table_id" is present in the map, otherwise return nil
656func GetNextTableId(kw OfpFlowModArgs) *uint32 {
657 if val, exist := kw["table_id"]; exist {
658 ret := uint32(val)
659 return &ret
660 }
661 return nil
662}
663
664// GetMeterIdFlowModArgs returns the meterId if the "meter_id" is present in the map, otherwise return 0
665func GetMeterIdFlowModArgs(kw OfpFlowModArgs) uint32 {
666 if val, exist := kw["meter_id"]; exist {
667 return uint32(val)
668 }
669 return 0
670}
671
672// Function returns the metadata if the "write_metadata" is present in the map, otherwise return nil
673func GetMetadataFlowModArgs(kw OfpFlowModArgs) uint64 {
674 if val, exist := kw["write_metadata"]; exist {
675 ret := uint64(val)
676 return ret
677 }
678 return 0
679}
680
Kent Hagermanf9cbe692020-05-05 17:50:26 -0400681// HashFlowStats returns a unique 64-bit integer hash of 'table_id', 'priority', and 'match'
682// The OF spec states that:
683// A flow table entry is identified by its match fields and priority: the match fields
684// and priority taken together identify a unique flow entry in the flow table.
Scott Baker6256a342020-02-21 15:36:26 -0800685func HashFlowStats(flow *ofp.OfpFlowStats) (uint64, error) {
Kent Hagermanf9cbe692020-05-05 17:50:26 -0400686 // first we need to make sure the oxm fields are in a predictable order (the specific order doesn't matter)
687 sort.Slice(flow.Match.OxmFields, func(a, b int) bool {
688 fieldsA, fieldsB := flow.Match.OxmFields[a], flow.Match.OxmFields[b]
689 if fieldsA.OxmClass < fieldsB.OxmClass {
690 return true
691 }
692 switch fieldA := fieldsA.Field.(type) {
693 case *ofp.OfpOxmField_OfbField:
694 switch fieldB := fieldsB.Field.(type) {
695 case *ofp.OfpOxmField_ExperimenterField:
696 return true // ofp < experimenter
697 case *ofp.OfpOxmField_OfbField:
698 return fieldA.OfbField.Type < fieldB.OfbField.Type
699 }
700 case *ofp.OfpOxmField_ExperimenterField:
701 switch fieldB := fieldsB.Field.(type) {
702 case *ofp.OfpOxmField_OfbField:
703 return false // ofp < experimenter
704 case *ofp.OfpOxmField_ExperimenterField:
705 eFieldA, eFieldB := fieldA.ExperimenterField, fieldB.ExperimenterField
706 if eFieldA.Experimenter != eFieldB.Experimenter {
707 return eFieldA.Experimenter < eFieldB.Experimenter
708 }
709 return eFieldA.OxmHeader < eFieldB.OxmHeader
710 }
711 }
712 return false
713 })
714
715 md5Hash := md5.New() // note that write errors will never occur with md5 hashing
716 var tmp [12]byte
717
718 binary.BigEndian.PutUint32(tmp[0:4], flow.TableId) // tableId
719 binary.BigEndian.PutUint32(tmp[4:8], flow.Priority) // priority
720 binary.BigEndian.PutUint32(tmp[8:12], uint32(flow.Match.Type)) // match type
721 _, _ = md5Hash.Write(tmp[:12])
722
723 for _, field := range flow.Match.OxmFields { // for all match fields
724 binary.BigEndian.PutUint32(tmp[:4], uint32(field.OxmClass)) // match class
725 _, _ = md5Hash.Write(tmp[:4])
726
727 switch oxmField := field.Field.(type) {
728 case *ofp.OfpOxmField_ExperimenterField:
729 binary.BigEndian.PutUint32(tmp[0:4], oxmField.ExperimenterField.Experimenter)
730 binary.BigEndian.PutUint32(tmp[4:8], oxmField.ExperimenterField.OxmHeader)
731 _, _ = md5Hash.Write(tmp[:8])
732
733 case *ofp.OfpOxmField_OfbField:
734 if err := hashWriteOfbField(md5Hash, oxmField.OfbField); err != nil {
735 return 0, err
736 }
737
738 default:
739 return 0, fmt.Errorf("unknown OfpOxmField type: %T", field.Field)
740 }
Scott Baker456b8932019-10-24 10:36:39 -0700741 }
Kent Hagermanf9cbe692020-05-05 17:50:26 -0400742
743 ret := md5Hash.Sum(nil)
744 return binary.BigEndian.Uint64(ret[0:8]), nil
745}
746
747func hashWriteOfbField(md5Hash hash.Hash, field *ofp.OfpOxmOfbField) error {
748 var tmp [8]byte
749 binary.BigEndian.PutUint32(tmp[:4], uint32(field.Type)) // type
750 _, _ = md5Hash.Write(tmp[:4])
751
752 // value
753 valType, val32, val64, valSlice := uint8(0), uint32(0), uint64(0), []byte(nil)
754 switch val := field.Value.(type) {
755 case *ofp.OfpOxmOfbField_Port:
756 valType, val32 = 4, val.Port
757 case *ofp.OfpOxmOfbField_PhysicalPort:
758 valType, val32 = 4, val.PhysicalPort
759 case *ofp.OfpOxmOfbField_TableMetadata:
760 valType, val64 = 8, val.TableMetadata
761 case *ofp.OfpOxmOfbField_EthDst:
762 valType, valSlice = 1, val.EthDst
763 case *ofp.OfpOxmOfbField_EthSrc:
764 valType, valSlice = 1, val.EthSrc
765 case *ofp.OfpOxmOfbField_EthType:
766 valType, val32 = 4, val.EthType
767 case *ofp.OfpOxmOfbField_VlanVid:
768 valType, val32 = 4, val.VlanVid
769 case *ofp.OfpOxmOfbField_VlanPcp:
770 valType, val32 = 4, val.VlanPcp
771 case *ofp.OfpOxmOfbField_IpDscp:
772 valType, val32 = 4, val.IpDscp
773 case *ofp.OfpOxmOfbField_IpEcn:
774 valType, val32 = 4, val.IpEcn
775 case *ofp.OfpOxmOfbField_IpProto:
776 valType, val32 = 4, val.IpProto
777 case *ofp.OfpOxmOfbField_Ipv4Src:
778 valType, val32 = 4, val.Ipv4Src
779 case *ofp.OfpOxmOfbField_Ipv4Dst:
780 valType, val32 = 4, val.Ipv4Dst
781 case *ofp.OfpOxmOfbField_TcpSrc:
782 valType, val32 = 4, val.TcpSrc
783 case *ofp.OfpOxmOfbField_TcpDst:
784 valType, val32 = 4, val.TcpDst
785 case *ofp.OfpOxmOfbField_UdpSrc:
786 valType, val32 = 4, val.UdpSrc
787 case *ofp.OfpOxmOfbField_UdpDst:
788 valType, val32 = 4, val.UdpDst
789 case *ofp.OfpOxmOfbField_SctpSrc:
790 valType, val32 = 4, val.SctpSrc
791 case *ofp.OfpOxmOfbField_SctpDst:
792 valType, val32 = 4, val.SctpDst
793 case *ofp.OfpOxmOfbField_Icmpv4Type:
794 valType, val32 = 4, val.Icmpv4Type
795 case *ofp.OfpOxmOfbField_Icmpv4Code:
796 valType, val32 = 4, val.Icmpv4Code
797 case *ofp.OfpOxmOfbField_ArpOp:
798 valType, val32 = 4, val.ArpOp
799 case *ofp.OfpOxmOfbField_ArpSpa:
800 valType, val32 = 4, val.ArpSpa
801 case *ofp.OfpOxmOfbField_ArpTpa:
802 valType, val32 = 4, val.ArpTpa
803 case *ofp.OfpOxmOfbField_ArpSha:
804 valType, valSlice = 1, val.ArpSha
805 case *ofp.OfpOxmOfbField_ArpTha:
806 valType, valSlice = 1, val.ArpTha
807 case *ofp.OfpOxmOfbField_Ipv6Src:
808 valType, valSlice = 1, val.Ipv6Src
809 case *ofp.OfpOxmOfbField_Ipv6Dst:
810 valType, valSlice = 1, val.Ipv6Dst
811 case *ofp.OfpOxmOfbField_Ipv6Flabel:
812 valType, val32 = 4, val.Ipv6Flabel
813 case *ofp.OfpOxmOfbField_Icmpv6Type:
814 valType, val32 = 4, val.Icmpv6Type
815 case *ofp.OfpOxmOfbField_Icmpv6Code:
816 valType, val32 = 4, val.Icmpv6Code
817 case *ofp.OfpOxmOfbField_Ipv6NdTarget:
818 valType, valSlice = 1, val.Ipv6NdTarget
819 case *ofp.OfpOxmOfbField_Ipv6NdSsl:
820 valType, valSlice = 1, val.Ipv6NdSsl
821 case *ofp.OfpOxmOfbField_Ipv6NdTll:
822 valType, valSlice = 1, val.Ipv6NdTll
823 case *ofp.OfpOxmOfbField_MplsLabel:
824 valType, val32 = 4, val.MplsLabel
825 case *ofp.OfpOxmOfbField_MplsTc:
826 valType, val32 = 4, val.MplsTc
827 case *ofp.OfpOxmOfbField_MplsBos:
828 valType, val32 = 4, val.MplsBos
829 case *ofp.OfpOxmOfbField_PbbIsid:
830 valType, val32 = 4, val.PbbIsid
831 case *ofp.OfpOxmOfbField_TunnelId:
832 valType, val64 = 8, val.TunnelId
833 case *ofp.OfpOxmOfbField_Ipv6Exthdr:
834 valType, val32 = 4, val.Ipv6Exthdr
835 default:
836 return fmt.Errorf("unknown OfpOxmField value type: %T", val)
Scott Baker456b8932019-10-24 10:36:39 -0700837 }
Kent Hagermanf9cbe692020-05-05 17:50:26 -0400838 switch valType {
839 case 1: // slice
840 _, _ = md5Hash.Write(valSlice)
841 case 4: // uint32
842 binary.BigEndian.PutUint32(tmp[:4], val32)
843 _, _ = md5Hash.Write(tmp[:4])
844 case 8: // uint64
845 binary.BigEndian.PutUint64(tmp[:8], val64)
846 _, _ = md5Hash.Write(tmp[:8])
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800847 }
Kent Hagermanf9cbe692020-05-05 17:50:26 -0400848
849 // mask
850 if !field.HasMask {
851 tmp[0] = 0x00
852 _, _ = md5Hash.Write(tmp[:1]) // match hasMask = false
853 } else {
854 tmp[0] = 0x01
855 _, _ = md5Hash.Write(tmp[:1]) // match hasMask = true
856
857 maskType, mask32, mask64, maskSlice := uint8(0), uint32(0), uint64(0), []byte(nil)
858 switch mask := field.Mask.(type) {
859 case *ofp.OfpOxmOfbField_TableMetadataMask:
860 maskType, mask64 = 8, mask.TableMetadataMask
861 case *ofp.OfpOxmOfbField_EthDstMask:
862 maskType, maskSlice = 1, mask.EthDstMask
863 case *ofp.OfpOxmOfbField_EthSrcMask:
864 maskType, maskSlice = 1, mask.EthSrcMask
865 case *ofp.OfpOxmOfbField_VlanVidMask:
866 maskType, mask32 = 4, mask.VlanVidMask
867 case *ofp.OfpOxmOfbField_Ipv4SrcMask:
868 maskType, mask32 = 4, mask.Ipv4SrcMask
869 case *ofp.OfpOxmOfbField_Ipv4DstMask:
870 maskType, mask32 = 4, mask.Ipv4DstMask
871 case *ofp.OfpOxmOfbField_ArpSpaMask:
872 maskType, mask32 = 4, mask.ArpSpaMask
873 case *ofp.OfpOxmOfbField_ArpTpaMask:
874 maskType, mask32 = 4, mask.ArpTpaMask
875 case *ofp.OfpOxmOfbField_Ipv6SrcMask:
876 maskType, maskSlice = 1, mask.Ipv6SrcMask
877 case *ofp.OfpOxmOfbField_Ipv6DstMask:
878 maskType, maskSlice = 1, mask.Ipv6DstMask
879 case *ofp.OfpOxmOfbField_Ipv6FlabelMask:
880 maskType, mask32 = 4, mask.Ipv6FlabelMask
881 case *ofp.OfpOxmOfbField_PbbIsidMask:
882 maskType, mask32 = 4, mask.PbbIsidMask
883 case *ofp.OfpOxmOfbField_TunnelIdMask:
884 maskType, mask64 = 8, mask.TunnelIdMask
885 case *ofp.OfpOxmOfbField_Ipv6ExthdrMask:
886 maskType, mask32 = 4, mask.Ipv6ExthdrMask
887 case nil:
888 return fmt.Errorf("hasMask set to true, but no mask present")
889 default:
890 return fmt.Errorf("unknown OfpOxmField mask type: %T", mask)
891 }
892 switch maskType {
893 case 1: // slice
894 _, _ = md5Hash.Write(maskSlice)
895 case 4: // uint32
896 binary.BigEndian.PutUint32(tmp[:4], mask32)
897 _, _ = md5Hash.Write(tmp[:4])
898 case 8: // uint64
899 binary.BigEndian.PutUint64(tmp[:8], mask64)
900 _, _ = md5Hash.Write(tmp[:8])
901 }
902 }
903 return nil
Scott Baker456b8932019-10-24 10:36:39 -0700904}
905
906// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
Scott Baker6256a342020-02-21 15:36:26 -0800907func FlowStatsEntryFromFlowModMessage(mod *ofp.OfpFlowMod) (*ofp.OfpFlowStats, error) {
Scott Baker456b8932019-10-24 10:36:39 -0700908 flow := &ofp.OfpFlowStats{}
909 if mod == nil {
Scott Baker6256a342020-02-21 15:36:26 -0800910 return flow, nil
Scott Baker456b8932019-10-24 10:36:39 -0700911 }
912 flow.TableId = mod.TableId
913 flow.Priority = mod.Priority
914 flow.IdleTimeout = mod.IdleTimeout
915 flow.HardTimeout = mod.HardTimeout
916 flow.Flags = mod.Flags
917 flow.Cookie = mod.Cookie
918 flow.Match = mod.Match
919 flow.Instructions = mod.Instructions
Scott Baker6256a342020-02-21 15:36:26 -0800920 var err error
921 if flow.Id, err = HashFlowStats(flow); err != nil {
922 return nil, err
923 }
924
925 return flow, nil
Scott Baker456b8932019-10-24 10:36:39 -0700926}
927
928func GroupEntryFromGroupMod(mod *ofp.OfpGroupMod) *ofp.OfpGroupEntry {
929 group := &ofp.OfpGroupEntry{}
930 if mod == nil {
931 return group
932 }
933 group.Desc = &ofp.OfpGroupDesc{Type: mod.Type, GroupId: mod.GroupId, Buckets: mod.Buckets}
934 group.Stats = &ofp.OfpGroupStats{GroupId: mod.GroupId}
935 //TODO do we need to instantiate bucket bins?
936 return group
937}
938
939// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
Scott Bakere6685952020-06-23 04:05:39 +0000940func MeterEntryFromMeterMod(meterMod *ofp.OfpMeterMod) *ofp.OfpMeterEntry {
Scott Baker456b8932019-10-24 10:36:39 -0700941 bandStats := make([]*ofp.OfpMeterBandStats, 0)
942 meter := &ofp.OfpMeterEntry{Config: &ofp.OfpMeterConfig{},
943 Stats: &ofp.OfpMeterStats{BandStats: bandStats}}
944 if meterMod == nil {
Scott Bakere6685952020-06-23 04:05:39 +0000945 logger.Error("Invalid meter mod command")
Scott Baker456b8932019-10-24 10:36:39 -0700946 return meter
947 }
948 // config init
949 meter.Config.MeterId = meterMod.MeterId
950 meter.Config.Flags = meterMod.Flags
951 meter.Config.Bands = meterMod.Bands
952 // meter stats init
953 meter.Stats.MeterId = meterMod.MeterId
954 meter.Stats.FlowCount = 0
955 meter.Stats.PacketInCount = 0
956 meter.Stats.ByteInCount = 0
957 meter.Stats.DurationSec = 0
958 meter.Stats.DurationNsec = 0
959 // band stats init
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800960 for range meterMod.Bands {
Scott Baker456b8932019-10-24 10:36:39 -0700961 band := &ofp.OfpMeterBandStats{}
962 band.PacketBandCount = 0
963 band.ByteBandCount = 0
964 bandStats = append(bandStats, band)
965 }
966 meter.Stats.BandStats = bandStats
Scott Bakere6685952020-06-23 04:05:39 +0000967 logger.Debugw("Allocated meter entry", log.Fields{"meter": *meter})
Scott Baker456b8932019-10-24 10:36:39 -0700968 return meter
969
970}
971
972func GetMeterIdFromFlow(flow *ofp.OfpFlowStats) uint32 {
973 if flow != nil {
974 for _, instruction := range flow.Instructions {
975 if instruction.Type == uint32(METER_ACTION) {
976 if meterInst := instruction.GetMeter(); meterInst != nil {
977 return meterInst.GetMeterId()
978 }
979 }
980 }
981 }
982
983 return uint32(0)
984}
985
986func MkOxmFields(matchFields []ofp.OfpOxmField) []*ofp.OfpOxmField {
987 oxmFields := make([]*ofp.OfpOxmField, 0)
988 for _, matchField := range matchFields {
989 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
990 oxmFields = append(oxmFields, &oxmField)
991 }
992 return oxmFields
993}
994
995func MkInstructionsFromActions(actions []*ofp.OfpAction) []*ofp.OfpInstruction {
996 instructions := make([]*ofp.OfpInstruction, 0)
997 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
998 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
999 instructions = append(instructions, &instruction)
1000 return instructions
1001}
1002
1003// Convenience function to generare ofp_flow_mod message with OXM BASIC match composed from the match_fields, and
1004// single APPLY_ACTIONS instruction with a list if ofp_action objects.
1005func MkSimpleFlowMod(matchFields []*ofp.OfpOxmField, actions []*ofp.OfpAction, command *ofp.OfpFlowModCommand, kw OfpFlowModArgs) *ofp.OfpFlowMod {
1006
1007 // Process actions instructions
1008 instructions := make([]*ofp.OfpInstruction, 0)
1009 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
1010 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
1011 instructions = append(instructions, &instruction)
1012
1013 // Process next table
1014 if tableId := GetNextTableId(kw); tableId != nil {
1015 var instGotoTable ofp.OfpInstruction_GotoTable
1016 instGotoTable.GotoTable = &ofp.OfpInstructionGotoTable{TableId: *tableId}
1017 inst := ofp.OfpInstruction{Type: uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE), Data: &instGotoTable}
1018 instructions = append(instructions, &inst)
1019 }
1020 // Process meter action
1021 if meterId := GetMeterIdFlowModArgs(kw); meterId != 0 {
1022 var instMeter ofp.OfpInstruction_Meter
1023 instMeter.Meter = &ofp.OfpInstructionMeter{MeterId: meterId}
1024 inst := ofp.OfpInstruction{Type: uint32(METER_ACTION), Data: &instMeter}
1025 instructions = append(instructions, &inst)
1026 }
1027 //process write_metadata action
1028 if metadata := GetMetadataFlowModArgs(kw); metadata != 0 {
1029 var instWriteMetadata ofp.OfpInstruction_WriteMetadata
1030 instWriteMetadata.WriteMetadata = &ofp.OfpInstructionWriteMetadata{Metadata: metadata}
1031 inst := ofp.OfpInstruction{Type: uint32(WRITE_METADATA), Data: &instWriteMetadata}
1032 instructions = append(instructions, &inst)
1033 }
1034
1035 // Process match fields
1036 oxmFields := make([]*ofp.OfpOxmField, 0)
1037 for _, matchField := range matchFields {
1038 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
1039 oxmFields = append(oxmFields, &oxmField)
1040 }
1041 var match ofp.OfpMatch
1042 match.Type = ofp.OfpMatchType_OFPMT_OXM
1043 match.OxmFields = oxmFields
1044
1045 // Create ofp_flow_message
1046 msg := &ofp.OfpFlowMod{}
1047 if command == nil {
1048 msg.Command = ofp.OfpFlowModCommand_OFPFC_ADD
1049 } else {
1050 msg.Command = *command
1051 }
1052 msg.Instructions = instructions
1053 msg.Match = &match
1054
1055 // Set the variadic argument values
1056 msg = setVariadicModAttributes(msg, kw)
1057
1058 return msg
1059}
1060
1061func MkMulticastGroupMod(groupId uint32, buckets []*ofp.OfpBucket, command *ofp.OfpGroupModCommand) *ofp.OfpGroupMod {
1062 group := &ofp.OfpGroupMod{}
1063 if command == nil {
1064 group.Command = ofp.OfpGroupModCommand_OFPGC_ADD
1065 } else {
1066 group.Command = *command
1067 }
1068 group.Type = ofp.OfpGroupType_OFPGT_ALL
1069 group.GroupId = groupId
1070 group.Buckets = buckets
1071 return group
1072}
1073
1074//SetVariadicModAttributes sets only uint64 or uint32 fields of the ofp_flow_mod message
1075func setVariadicModAttributes(mod *ofp.OfpFlowMod, args OfpFlowModArgs) *ofp.OfpFlowMod {
1076 if args == nil {
1077 return mod
1078 }
1079 for key, val := range args {
1080 switch key {
1081 case "cookie":
1082 mod.Cookie = val
1083 case "cookie_mask":
1084 mod.CookieMask = val
1085 case "table_id":
1086 mod.TableId = uint32(val)
1087 case "idle_timeout":
1088 mod.IdleTimeout = uint32(val)
1089 case "hard_timeout":
1090 mod.HardTimeout = uint32(val)
1091 case "priority":
1092 mod.Priority = uint32(val)
1093 case "buffer_id":
1094 mod.BufferId = uint32(val)
1095 case "out_port":
1096 mod.OutPort = uint32(val)
1097 case "out_group":
1098 mod.OutGroup = uint32(val)
1099 case "flags":
1100 mod.Flags = uint32(val)
1101 }
1102 }
1103 return mod
1104}
1105
1106func MkPacketIn(port uint32, packet []byte) *ofp.OfpPacketIn {
1107 packetIn := &ofp.OfpPacketIn{
1108 Reason: ofp.OfpPacketInReason_OFPR_ACTION,
1109 Match: &ofp.OfpMatch{
1110 Type: ofp.OfpMatchType_OFPMT_OXM,
1111 OxmFields: []*ofp.OfpOxmField{
1112 {
1113 OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
1114 Field: &ofp.OfpOxmField_OfbField{
1115 OfbField: InPort(port)},
1116 },
1117 },
1118 },
1119 Data: packet,
1120 }
1121 return packetIn
1122}
1123
1124// MkFlowStat is a helper method to build flows
Scott Baker6256a342020-02-21 15:36:26 -08001125func MkFlowStat(fa *FlowArgs) (*ofp.OfpFlowStats, error) {
Scott Baker456b8932019-10-24 10:36:39 -07001126 //Build the match-fields
1127 matchFields := make([]*ofp.OfpOxmField, 0)
1128 for _, val := range fa.MatchFields {
1129 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
1130 }
1131 return FlowStatsEntryFromFlowModMessage(MkSimpleFlowMod(matchFields, fa.Actions, fa.Command, fa.KV))
1132}
1133
1134func MkGroupStat(ga *GroupArgs) *ofp.OfpGroupEntry {
1135 return GroupEntryFromGroupMod(MkMulticastGroupMod(ga.GroupId, ga.Buckets, ga.Command))
1136}
1137
1138type OfpFlowModArgs map[string]uint64
1139
1140type FlowArgs struct {
1141 MatchFields []*ofp.OfpOxmOfbField
1142 Actions []*ofp.OfpAction
1143 Command *ofp.OfpFlowModCommand
1144 Priority uint32
1145 KV OfpFlowModArgs
1146}
1147
1148type GroupArgs struct {
1149 GroupId uint32
1150 Buckets []*ofp.OfpBucket
1151 Command *ofp.OfpGroupModCommand
1152}
1153
1154type FlowsAndGroups struct {
1155 Flows *ordered_map.OrderedMap
1156 Groups *ordered_map.OrderedMap
1157}
1158
1159func NewFlowsAndGroups() *FlowsAndGroups {
1160 var fg FlowsAndGroups
1161 fg.Flows = ordered_map.NewOrderedMap()
1162 fg.Groups = ordered_map.NewOrderedMap()
1163 return &fg
1164}
1165
1166func (fg *FlowsAndGroups) Copy() *FlowsAndGroups {
1167 copyFG := NewFlowsAndGroups()
1168 iter := fg.Flows.IterFunc()
1169 for kv, ok := iter(); ok; kv, ok = iter() {
1170 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1171 copyFG.Flows.Set(kv.Key, proto.Clone(protoMsg))
1172 }
1173 }
1174 iter = fg.Groups.IterFunc()
1175 for kv, ok := iter(); ok; kv, ok = iter() {
1176 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1177 copyFG.Groups.Set(kv.Key, proto.Clone(protoMsg))
1178 }
1179 }
1180 return copyFG
1181}
1182
1183func (fg *FlowsAndGroups) GetFlow(index int) *ofp.OfpFlowStats {
1184 iter := fg.Flows.IterFunc()
1185 pos := 0
1186 for kv, ok := iter(); ok; kv, ok = iter() {
1187 if pos == index {
1188 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1189 return protoMsg
1190 }
1191 return nil
1192 }
1193 pos += 1
1194 }
1195 return nil
1196}
1197
1198func (fg *FlowsAndGroups) ListFlows() []*ofp.OfpFlowStats {
1199 flows := make([]*ofp.OfpFlowStats, 0)
1200 iter := fg.Flows.IterFunc()
1201 for kv, ok := iter(); ok; kv, ok = iter() {
1202 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1203 flows = append(flows, protoMsg)
1204 }
1205 }
1206 return flows
1207}
1208
1209func (fg *FlowsAndGroups) ListGroups() []*ofp.OfpGroupEntry {
1210 groups := make([]*ofp.OfpGroupEntry, 0)
1211 iter := fg.Groups.IterFunc()
1212 for kv, ok := iter(); ok; kv, ok = iter() {
1213 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1214 groups = append(groups, protoMsg)
1215 }
1216 }
1217 return groups
1218}
1219
1220func (fg *FlowsAndGroups) String() string {
1221 var buffer bytes.Buffer
1222 iter := fg.Flows.IterFunc()
1223 for kv, ok := iter(); ok; kv, ok = iter() {
1224 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1225 buffer.WriteString("\nFlow:\n")
1226 buffer.WriteString(proto.MarshalTextString(protoMsg))
1227 buffer.WriteString("\n")
1228 }
1229 }
1230 iter = fg.Groups.IterFunc()
1231 for kv, ok := iter(); ok; kv, ok = iter() {
1232 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1233 buffer.WriteString("\nGroup:\n")
1234 buffer.WriteString(proto.MarshalTextString(protoMsg))
1235 buffer.WriteString("\n")
1236 }
1237 }
1238 return buffer.String()
1239}
1240
1241func (fg *FlowsAndGroups) AddFlow(flow *ofp.OfpFlowStats) {
1242 if flow == nil {
1243 return
1244 }
1245
1246 if fg.Flows == nil {
1247 fg.Flows = ordered_map.NewOrderedMap()
1248 }
1249 if fg.Groups == nil {
1250 fg.Groups = ordered_map.NewOrderedMap()
1251 }
1252 //Add flow only if absent
1253 if _, exist := fg.Flows.Get(flow.Id); !exist {
1254 fg.Flows.Set(flow.Id, flow)
1255 }
1256}
1257
1258func (fg *FlowsAndGroups) AddGroup(group *ofp.OfpGroupEntry) {
1259 if group == nil {
1260 return
1261 }
1262
1263 if fg.Flows == nil {
1264 fg.Flows = ordered_map.NewOrderedMap()
1265 }
1266 if fg.Groups == nil {
1267 fg.Groups = ordered_map.NewOrderedMap()
1268 }
1269 //Add group only if absent
1270 if _, exist := fg.Groups.Get(group.Desc.GroupId); !exist {
1271 fg.Groups.Set(group.Desc.GroupId, group)
1272 }
1273}
1274
1275//AddFrom add flows and groups from the argument into this structure only if they do not already exist
1276func (fg *FlowsAndGroups) AddFrom(from *FlowsAndGroups) {
1277 iter := from.Flows.IterFunc()
1278 for kv, ok := iter(); ok; kv, ok = iter() {
1279 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1280 if _, exist := fg.Flows.Get(protoMsg.Id); !exist {
1281 fg.Flows.Set(protoMsg.Id, protoMsg)
1282 }
1283 }
1284 }
1285 iter = from.Groups.IterFunc()
1286 for kv, ok := iter(); ok; kv, ok = iter() {
1287 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1288 if _, exist := fg.Groups.Get(protoMsg.Stats.GroupId); !exist {
1289 fg.Groups.Set(protoMsg.Stats.GroupId, protoMsg)
1290 }
1291 }
1292 }
1293}
1294
1295type DeviceRules struct {
1296 Rules map[string]*FlowsAndGroups
1297}
1298
1299func NewDeviceRules() *DeviceRules {
1300 var dr DeviceRules
1301 dr.Rules = make(map[string]*FlowsAndGroups)
1302 return &dr
1303}
1304
1305func (dr *DeviceRules) Copy() *DeviceRules {
1306 copyDR := NewDeviceRules()
1307 if dr != nil {
1308 for key, val := range dr.Rules {
1309 if val != nil {
1310 copyDR.Rules[key] = val.Copy()
1311 }
1312 }
1313 }
1314 return copyDR
1315}
1316
1317func (dr *DeviceRules) ClearFlows(deviceId string) {
1318 if _, exist := dr.Rules[deviceId]; exist {
1319 dr.Rules[deviceId].Flows = ordered_map.NewOrderedMap()
1320 }
1321}
1322
1323func (dr *DeviceRules) FilterRules(deviceIds map[string]string) *DeviceRules {
1324 filteredDR := NewDeviceRules()
1325 for key, val := range dr.Rules {
1326 if _, exist := deviceIds[key]; exist {
1327 filteredDR.Rules[key] = val.Copy()
1328 }
1329 }
1330 return filteredDR
1331}
1332
1333func (dr *DeviceRules) AddFlow(deviceId string, flow *ofp.OfpFlowStats) {
1334 if _, exist := dr.Rules[deviceId]; !exist {
1335 dr.Rules[deviceId] = NewFlowsAndGroups()
1336 }
1337 dr.Rules[deviceId].AddFlow(flow)
1338}
1339
1340func (dr *DeviceRules) GetRules() map[string]*FlowsAndGroups {
1341 return dr.Rules
1342}
1343
1344func (dr *DeviceRules) String() string {
1345 var buffer bytes.Buffer
1346 for key, value := range dr.Rules {
1347 buffer.WriteString("DeviceId:")
1348 buffer.WriteString(key)
1349 buffer.WriteString(value.String())
1350 buffer.WriteString("\n\n")
1351 }
1352 return buffer.String()
1353}
1354
1355func (dr *DeviceRules) AddFlowsAndGroup(deviceId string, fg *FlowsAndGroups) {
1356 if _, ok := dr.Rules[deviceId]; !ok {
1357 dr.Rules[deviceId] = NewFlowsAndGroups()
1358 }
1359 dr.Rules[deviceId] = fg
1360}
1361
1362// CreateEntryIfNotExist creates a new deviceId in the Map if it does not exist and assigns an
1363// empty FlowsAndGroups to it. Otherwise, it does nothing.
1364func (dr *DeviceRules) CreateEntryIfNotExist(deviceId string) {
1365 if _, ok := dr.Rules[deviceId]; !ok {
1366 dr.Rules[deviceId] = NewFlowsAndGroups()
1367 }
1368}
1369
1370/*
1371 * Common flow routines
1372 */
1373
1374//FindOverlappingFlows return a list of overlapping flow(s) where mod is the flow request
1375func FindOverlappingFlows(flows []*ofp.OfpFlowStats, mod *ofp.OfpFlowMod) []*ofp.OfpFlowStats {
1376 return nil //TODO - complete implementation
1377}
1378
1379// FindFlowById returns the index of the flow in the flows array if present. Otherwise, it returns -1
1380func FindFlowById(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
1381 for idx, f := range flows {
1382 if flow.Id == f.Id {
1383 return idx
1384 }
1385 }
1386 return -1
1387}
1388
1389// FindFlows returns the index in flows where flow if present. Otherwise, it returns -1
1390func FindFlows(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
1391 for idx, f := range flows {
Kent Hagermanf9cbe692020-05-05 17:50:26 -04001392 if f.Id == flow.Id {
Scott Baker456b8932019-10-24 10:36:39 -07001393 return idx
1394 }
1395 }
1396 return -1
1397}
1398
1399//FlowMatch returns true if two flows matches on the following flow attributes:
1400//TableId, Priority, Flags, Cookie, Match
1401func FlowMatch(f1 *ofp.OfpFlowStats, f2 *ofp.OfpFlowStats) bool {
Kent Hagermanf9cbe692020-05-05 17:50:26 -04001402 return f1 != nil && f2 != nil && f1.Id == f2.Id
Scott Baker456b8932019-10-24 10:36:39 -07001403}
1404
1405//FlowMatchesMod returns True if given flow is "covered" by the wildcard flow_mod, taking into consideration of
1406//both exact matches as well as masks-based match fields if any. Otherwise return False
1407func FlowMatchesMod(flow *ofp.OfpFlowStats, mod *ofp.OfpFlowMod) bool {
1408 if flow == nil || mod == nil {
1409 return false
1410 }
1411 //Check if flow.cookie is covered by mod.cookie and mod.cookie_mask
1412 if (flow.Cookie & mod.CookieMask) != (mod.Cookie & mod.CookieMask) {
1413 return false
1414 }
1415
1416 //Check if flow.table_id is covered by flow_mod.table_id
1417 if mod.TableId != uint32(ofp.OfpTable_OFPTT_ALL) && flow.TableId != mod.TableId {
1418 return false
1419 }
1420
1421 //Check out_port
1422 if (mod.OutPort&0x7fffffff) != uint32(ofp.OfpPortNo_OFPP_ANY) && !FlowHasOutPort(flow, mod.OutPort) {
1423 return false
1424 }
1425
1426 // Check out_group
1427 if (mod.OutGroup&0x7fffffff) != uint32(ofp.OfpGroup_OFPG_ANY) && !FlowHasOutGroup(flow, mod.OutGroup) {
1428 return false
1429 }
1430
1431 //Priority is ignored
1432
1433 //Check match condition
1434 //If the flow_mod match field is empty, that is a special case and indicates the flow entry matches
1435 if (mod.Match == nil) || (mod.Match.OxmFields == nil) || (len(mod.Match.OxmFields) == 0) {
1436 //If we got this far and the match is empty in the flow spec, than the flow matches
1437 return true
1438 } // TODO : implement the flow match analysis
1439 return false
1440
1441}
1442
1443//FlowHasOutPort returns True if flow has a output command with the given out_port
1444func FlowHasOutPort(flow *ofp.OfpFlowStats, outPort uint32) bool {
1445 if flow == nil {
1446 return false
1447 }
1448 for _, instruction := range flow.Instructions {
1449 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
1450 if instruction.GetActions() == nil {
1451 return false
1452 }
1453 for _, action := range instruction.GetActions().Actions {
1454 if action.Type == ofp.OfpActionType_OFPAT_OUTPUT {
1455 if (action.GetOutput() != nil) && (action.GetOutput().Port == outPort) {
1456 return true
1457 }
1458 }
1459
1460 }
1461 }
1462 }
1463 return false
1464}
1465
1466//FlowHasOutGroup return True if flow has a output command with the given out_group
1467func FlowHasOutGroup(flow *ofp.OfpFlowStats, groupID uint32) bool {
1468 if flow == nil {
1469 return false
1470 }
1471 for _, instruction := range flow.Instructions {
1472 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
1473 if instruction.GetActions() == nil {
1474 return false
1475 }
1476 for _, action := range instruction.GetActions().Actions {
1477 if action.Type == ofp.OfpActionType_OFPAT_GROUP {
1478 if (action.GetGroup() != nil) && (action.GetGroup().GroupId == groupID) {
1479 return true
1480 }
1481 }
1482
1483 }
1484 }
1485 }
1486 return false
1487}
1488
1489//FindGroup returns index of group if found, else returns -1
1490func FindGroup(groups []*ofp.OfpGroupEntry, groupId uint32) int {
1491 for idx, group := range groups {
1492 if group.Desc.GroupId == groupId {
1493 return idx
1494 }
1495 }
1496 return -1
1497}
1498
1499func FlowsDeleteByGroupId(flows []*ofp.OfpFlowStats, groupId uint32) (bool, []*ofp.OfpFlowStats) {
1500 toKeep := make([]*ofp.OfpFlowStats, 0)
1501
1502 for _, f := range flows {
1503 if !FlowHasOutGroup(f, groupId) {
1504 toKeep = append(toKeep, f)
1505 }
1506 }
1507 return len(toKeep) < len(flows), toKeep
1508}
1509
1510func ToOfpOxmField(from []*ofp.OfpOxmOfbField) []*ofp.OfpOxmField {
1511 matchFields := make([]*ofp.OfpOxmField, 0)
1512 for _, val := range from {
1513 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
1514 }
1515 return matchFields
1516}
Esin Karaman20b6de92019-11-05 08:29:16 +00001517
1518//IsMulticastIp returns true if the ip starts with the byte sequence of 1110;
1519//false otherwise.
1520func IsMulticastIp(ip uint32) bool {
1521 return ip>>28 == 14
1522}
1523
1524//ConvertToMulticastMacInt returns equivalent mac address of the given multicast ip address
1525func ConvertToMulticastMacInt(ip uint32) uint64 {
1526 //get last 23 bits of ip address by ip & 00000000011111111111111111111111
1527 theLast23BitsOfIp := ip & 8388607
1528 // perform OR with 0x1005E000000 to build mcast mac address
1529 return 1101088686080 | uint64(theLast23BitsOfIp)
1530}
1531
1532//ConvertToMulticastMacBytes returns equivalent mac address of the given multicast ip address
1533func ConvertToMulticastMacBytes(ip uint32) []byte {
1534 mac := ConvertToMulticastMacInt(ip)
1535 var b bytes.Buffer
1536 // catalyze (48 bits) in binary:111111110000000000000000000000000000000000000000
1537 catalyze := uint64(280375465082880)
1538 //convert each octet to decimal
1539 for i := 0; i < 6; i++ {
1540 if i != 0 {
1541 catalyze = catalyze >> 8
1542 }
1543 octet := mac & catalyze
1544 octetDecimal := octet >> uint8(40-i*8)
1545 b.WriteByte(byte(octetDecimal))
1546 }
1547 return b.Bytes()
1548}