blob: 3828b39a09686808442e80343bc16c9ba6ebe5e2 [file] [log] [blame]
khenaidoo89b0e942018-10-21 21:11:33 -04001/*
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 utils
17
18import (
19 "bytes"
khenaidoo68c930b2019-05-13 11:46:51 -040020 "crypto/md5"
21 "fmt"
khenaidoo89b0e942018-10-21 21:11:33 -040022 "github.com/cevaris/ordered_map"
23 "github.com/gogo/protobuf/proto"
khenaidoo68c930b2019-05-13 11:46:51 -040024 "github.com/opencord/voltha-go/common/log"
William Kurkiandaa6bb22019-03-07 12:26:28 -050025 ofp "github.com/opencord/voltha-protos/go/openflow_13"
khenaidoo68c930b2019-05-13 11:46:51 -040026 "math/big"
khenaidoo19d7b632018-10-30 10:49:50 -040027 "strings"
khenaidoo89b0e942018-10-21 21:11:33 -040028)
29
khenaidoo68c930b2019-05-13 11:46:51 -040030var (
31 // Instructions shortcut
32 APPLY_ACTIONS = ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS
33
34 //OFPAT_* shortcuts
35 OUTPUT = ofp.OfpActionType_OFPAT_OUTPUT
36 COPY_TTL_OUT = ofp.OfpActionType_OFPAT_COPY_TTL_OUT
37 COPY_TTL_IN = ofp.OfpActionType_OFPAT_COPY_TTL_IN
38 SET_MPLS_TTL = ofp.OfpActionType_OFPAT_SET_MPLS_TTL
39 DEC_MPLS_TTL = ofp.OfpActionType_OFPAT_DEC_MPLS_TTL
40 PUSH_VLAN = ofp.OfpActionType_OFPAT_PUSH_VLAN
41 POP_VLAN = ofp.OfpActionType_OFPAT_POP_VLAN
42 PUSH_MPLS = ofp.OfpActionType_OFPAT_PUSH_MPLS
43 POP_MPLS = ofp.OfpActionType_OFPAT_POP_MPLS
44 SET_QUEUE = ofp.OfpActionType_OFPAT_SET_QUEUE
45 GROUP = ofp.OfpActionType_OFPAT_GROUP
46 SET_NW_TTL = ofp.OfpActionType_OFPAT_SET_NW_TTL
47 NW_TTL = ofp.OfpActionType_OFPAT_DEC_NW_TTL
48 SET_FIELD = ofp.OfpActionType_OFPAT_SET_FIELD
49 PUSH_PBB = ofp.OfpActionType_OFPAT_PUSH_PBB
50 POP_PBB = ofp.OfpActionType_OFPAT_POP_PBB
51 EXPERIMENTER = ofp.OfpActionType_OFPAT_EXPERIMENTER
52
53 //OFPXMT_OFB_* shortcuts (incomplete)
54 IN_PORT = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT
55 IN_PHY_PORT = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT
56 METADATA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_METADATA
57 ETH_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_DST
58 ETH_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_SRC
59 ETH_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE
60 VLAN_VID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID
61 VLAN_PCP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP
62 IP_DSCP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_DSCP
63 IP_ECN = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_ECN
64 IP_PROTO = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO
65 IPV4_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_SRC
66 IPV4_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST
67 TCP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TCP_SRC
68 TCP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TCP_DST
69 UDP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC
70 UDP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST
71 SCTP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_SCTP_SRC
72 SCTP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_SCTP_DST
73 ICMPV4_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV4_TYPE
74 ICMPV4_CODE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV4_CODE
75 ARP_OP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_OP
76 ARP_SPA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_SPA
77 ARP_TPA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_TPA
78 ARP_SHA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_SHA
79 ARP_THA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_THA
80 IPV6_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_SRC
81 IPV6_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_DST
82 IPV6_FLABEL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_FLABEL
83 ICMPV6_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV6_TYPE
84 ICMPV6_CODE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV6_CODE
85 IPV6_ND_TARGET = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_TARGET
86 OFB_IPV6_ND_SLL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_SLL
87 IPV6_ND_TLL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_TLL
88 MPLS_LABEL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_LABEL
89 MPLS_TC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_TC
90 MPLS_BOS = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_BOS
91 PBB_ISID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_PBB_ISID
92 TUNNEL_ID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TUNNEL_ID
93 IPV6_EXTHDR = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_EXTHDR
94)
95
96//ofp_action_* shortcuts
97
98func Output(port uint32, maxLen ...ofp.OfpControllerMaxLen) *ofp.OfpAction {
99 maxLength := ofp.OfpControllerMaxLen_OFPCML_MAX
100 if len(maxLen) > 0 {
101 maxLength = maxLen[0]
102 }
103 return &ofp.OfpAction{Type: OUTPUT, Action: &ofp.OfpAction_Output{Output: &ofp.OfpActionOutput{Port: port, MaxLen: uint32(maxLength)}}}
104}
105
106func MplsTtl(ttl uint32) *ofp.OfpAction {
107 return &ofp.OfpAction{Type: SET_MPLS_TTL, Action: &ofp.OfpAction_MplsTtl{MplsTtl: &ofp.OfpActionMplsTtl{MplsTtl: ttl}}}
108}
109
110func PushVlan(ethType uint32) *ofp.OfpAction {
111 return &ofp.OfpAction{Type: PUSH_VLAN, Action: &ofp.OfpAction_Push{Push: &ofp.OfpActionPush{Ethertype: ethType}}}
112}
113
114func PopVlan() *ofp.OfpAction {
115 return &ofp.OfpAction{Type: POP_VLAN}
116}
117
118func PopMpls(ethType uint32) *ofp.OfpAction {
119 return &ofp.OfpAction{Type: POP_MPLS, Action: &ofp.OfpAction_PopMpls{PopMpls: &ofp.OfpActionPopMpls{Ethertype: ethType}}}
120}
121
122func Group(groupId uint32) *ofp.OfpAction {
123 return &ofp.OfpAction{Type: GROUP, Action: &ofp.OfpAction_Group{Group: &ofp.OfpActionGroup{GroupId: groupId}}}
124}
125
126func NwTtl(nwTtl uint32) *ofp.OfpAction {
127 return &ofp.OfpAction{Type: NW_TTL, Action: &ofp.OfpAction_NwTtl{NwTtl: &ofp.OfpActionNwTtl{NwTtl: nwTtl}}}
128}
129
130func SetField(field *ofp.OfpOxmOfbField) *ofp.OfpAction {
131 actionSetField := &ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: &ofp.OfpOxmField_OfbField{OfbField: field}}
132 return &ofp.OfpAction{Type: SET_FIELD, Action: &ofp.OfpAction_SetField{SetField: &ofp.OfpActionSetField{Field: actionSetField}}}
133}
134
135func Experimenter(experimenter uint32, data []byte) *ofp.OfpAction {
136 return &ofp.OfpAction{Type: EXPERIMENTER, Action: &ofp.OfpAction_Experimenter{Experimenter: &ofp.OfpActionExperimenter{Experimenter: experimenter, Data: data}}}
137}
138
139//ofb_field generators (incomplete set)
140
141func InPort(inPort uint32) *ofp.OfpOxmOfbField {
142 return &ofp.OfpOxmOfbField{Type: IN_PORT, Value: &ofp.OfpOxmOfbField_Port{Port: inPort}}
143}
144
145func InPhyPort(inPhyPort uint32) *ofp.OfpOxmOfbField {
146 return &ofp.OfpOxmOfbField{Type: IN_PHY_PORT, Value: &ofp.OfpOxmOfbField_Port{Port: inPhyPort}}
147}
148
149func Metadata_ofp(tableMetadata uint64) *ofp.OfpOxmOfbField {
150 return &ofp.OfpOxmOfbField{Type: METADATA, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: tableMetadata}}
151}
152
153// should Metadata_ofp used here ?????
154func EthDst(ethDst uint64) *ofp.OfpOxmOfbField {
155 return &ofp.OfpOxmOfbField{Type: ETH_DST, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: ethDst}}
156}
157
158// should Metadata_ofp used here ?????
159func EthSrc(ethSrc uint64) *ofp.OfpOxmOfbField {
160 return &ofp.OfpOxmOfbField{Type: ETH_SRC, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: ethSrc}}
161}
162
163func EthType(ethType uint32) *ofp.OfpOxmOfbField {
164 return &ofp.OfpOxmOfbField{Type: ETH_TYPE, Value: &ofp.OfpOxmOfbField_EthType{EthType: ethType}}
165}
166
167func VlanVid(vlanVid uint32) *ofp.OfpOxmOfbField {
168 return &ofp.OfpOxmOfbField{Type: VLAN_VID, Value: &ofp.OfpOxmOfbField_VlanVid{VlanVid: vlanVid}}
169}
170
171func VlanPcp(vlanPcp uint32) *ofp.OfpOxmOfbField {
172 return &ofp.OfpOxmOfbField{Type: VLAN_PCP, Value: &ofp.OfpOxmOfbField_VlanPcp{VlanPcp: vlanPcp}}
173}
174
175func IpDscp(ipDscp uint32) *ofp.OfpOxmOfbField {
176 return &ofp.OfpOxmOfbField{Type: IP_DSCP, Value: &ofp.OfpOxmOfbField_IpDscp{IpDscp: ipDscp}}
177}
178
179func IpEcn(ipEcn uint32) *ofp.OfpOxmOfbField {
180 return &ofp.OfpOxmOfbField{Type: IP_ECN, Value: &ofp.OfpOxmOfbField_IpEcn{IpEcn: ipEcn}}
181}
182
183func IpProto(ipProto uint32) *ofp.OfpOxmOfbField {
184 return &ofp.OfpOxmOfbField{Type: IP_PROTO, Value: &ofp.OfpOxmOfbField_IpProto{IpProto: ipProto}}
185}
186
187func Ipv4Src(ipv4Src uint32) *ofp.OfpOxmOfbField {
188 return &ofp.OfpOxmOfbField{Type: IPV4_SRC, Value: &ofp.OfpOxmOfbField_Ipv4Src{Ipv4Src: ipv4Src}}
189}
190
191func Ipv4Dst(ipv4Dst uint32) *ofp.OfpOxmOfbField {
192 return &ofp.OfpOxmOfbField{Type: IPV4_DST, Value: &ofp.OfpOxmOfbField_Ipv4Dst{Ipv4Dst: ipv4Dst}}
193}
194
195func TcpSrc(tcpSrc uint32) *ofp.OfpOxmOfbField {
196 return &ofp.OfpOxmOfbField{Type: TCP_SRC, Value: &ofp.OfpOxmOfbField_TcpSrc{TcpSrc: tcpSrc}}
197}
198
199func TcpDst(tcpDst uint32) *ofp.OfpOxmOfbField {
200 return &ofp.OfpOxmOfbField{Type: TCP_DST, Value: &ofp.OfpOxmOfbField_TcpDst{TcpDst: tcpDst}}
201}
202
203func UdpSrc(udpSrc uint32) *ofp.OfpOxmOfbField {
204 return &ofp.OfpOxmOfbField{Type: UDP_SRC, Value: &ofp.OfpOxmOfbField_UdpSrc{UdpSrc: udpSrc}}
205}
206
207func UdpDst(udpDst uint32) *ofp.OfpOxmOfbField {
208 return &ofp.OfpOxmOfbField{Type: UDP_DST, Value: &ofp.OfpOxmOfbField_UdpDst{UdpDst: udpDst}}
209}
210
211func SctpSrc(sctpSrc uint32) *ofp.OfpOxmOfbField {
212 return &ofp.OfpOxmOfbField{Type: SCTP_SRC, Value: &ofp.OfpOxmOfbField_SctpSrc{SctpSrc: sctpSrc}}
213}
214
215func SctpDst(sctpDst uint32) *ofp.OfpOxmOfbField {
216 return &ofp.OfpOxmOfbField{Type: SCTP_DST, Value: &ofp.OfpOxmOfbField_SctpDst{SctpDst: sctpDst}}
217}
218
219func Icmpv4Type(icmpv4Type uint32) *ofp.OfpOxmOfbField {
220 return &ofp.OfpOxmOfbField{Type: ICMPV4_TYPE, Value: &ofp.OfpOxmOfbField_Icmpv4Type{Icmpv4Type: icmpv4Type}}
221}
222
223func Icmpv4Code(icmpv4Code uint32) *ofp.OfpOxmOfbField {
224 return &ofp.OfpOxmOfbField{Type: ICMPV4_CODE, Value: &ofp.OfpOxmOfbField_Icmpv4Code{Icmpv4Code: icmpv4Code}}
225}
226
227func ArpOp(arpOp uint32) *ofp.OfpOxmOfbField {
228 return &ofp.OfpOxmOfbField{Type: ARP_OP, Value: &ofp.OfpOxmOfbField_ArpOp{ArpOp: arpOp}}
229}
230
231func ArpSpa(arpSpa uint32) *ofp.OfpOxmOfbField {
232 return &ofp.OfpOxmOfbField{Type: ARP_SPA, Value: &ofp.OfpOxmOfbField_ArpSpa{ArpSpa: arpSpa}}
233}
234
235func ArpTpa(arpTpa uint32) *ofp.OfpOxmOfbField {
236 return &ofp.OfpOxmOfbField{Type: ARP_TPA, Value: &ofp.OfpOxmOfbField_ArpTpa{ArpTpa: arpTpa}}
237}
238
239func ArpSha(arpSha []byte) *ofp.OfpOxmOfbField {
240 return &ofp.OfpOxmOfbField{Type: ARP_SHA, Value: &ofp.OfpOxmOfbField_ArpSha{ArpSha: arpSha}}
241}
242
243func ArpTha(arpTha []byte) *ofp.OfpOxmOfbField {
244 return &ofp.OfpOxmOfbField{Type: ARP_THA, Value: &ofp.OfpOxmOfbField_ArpTha{ArpTha: arpTha}}
245}
246
247func Ipv6Src(ipv6Src []byte) *ofp.OfpOxmOfbField {
248 return &ofp.OfpOxmOfbField{Type: IPV6_SRC, Value: &ofp.OfpOxmOfbField_Ipv6Src{Ipv6Src: ipv6Src}}
249}
250
251func Ipv6Dst(ipv6Dst []byte) *ofp.OfpOxmOfbField {
252 return &ofp.OfpOxmOfbField{Type: IPV6_DST, Value: &ofp.OfpOxmOfbField_Ipv6Dst{Ipv6Dst: ipv6Dst}}
253}
254
255func Ipv6Flabel(ipv6Flabel uint32) *ofp.OfpOxmOfbField {
256 return &ofp.OfpOxmOfbField{Type: IPV6_FLABEL, Value: &ofp.OfpOxmOfbField_Ipv6Flabel{Ipv6Flabel: ipv6Flabel}}
257}
258
259func Icmpv6Type(icmpv6Type uint32) *ofp.OfpOxmOfbField {
260 return &ofp.OfpOxmOfbField{Type: ICMPV6_TYPE, Value: &ofp.OfpOxmOfbField_Icmpv6Type{Icmpv6Type: icmpv6Type}}
261}
262
263func Icmpv6Code(icmpv6Code uint32) *ofp.OfpOxmOfbField {
264 return &ofp.OfpOxmOfbField{Type: ICMPV6_CODE, Value: &ofp.OfpOxmOfbField_Icmpv6Code{Icmpv6Code: icmpv6Code}}
265}
266
267func Ipv6NdTarget(ipv6NdTarget []byte) *ofp.OfpOxmOfbField {
268 return &ofp.OfpOxmOfbField{Type: IPV6_ND_TARGET, Value: &ofp.OfpOxmOfbField_Ipv6NdTarget{Ipv6NdTarget: ipv6NdTarget}}
269}
270
271func OfbIpv6NdSll(ofbIpv6NdSll []byte) *ofp.OfpOxmOfbField {
272 return &ofp.OfpOxmOfbField{Type: OFB_IPV6_ND_SLL, Value: &ofp.OfpOxmOfbField_Ipv6NdSsl{Ipv6NdSsl: ofbIpv6NdSll}}
273}
274
275func Ipv6NdTll(ipv6NdTll []byte) *ofp.OfpOxmOfbField {
276 return &ofp.OfpOxmOfbField{Type: IPV6_ND_TLL, Value: &ofp.OfpOxmOfbField_Ipv6NdTll{Ipv6NdTll: ipv6NdTll}}
277}
278
279func MplsLabel(mplsLabel uint32) *ofp.OfpOxmOfbField {
280 return &ofp.OfpOxmOfbField{Type: MPLS_LABEL, Value: &ofp.OfpOxmOfbField_MplsLabel{MplsLabel: mplsLabel}}
281}
282
283func MplsTc(mplsTc uint32) *ofp.OfpOxmOfbField {
284 return &ofp.OfpOxmOfbField{Type: MPLS_TC, Value: &ofp.OfpOxmOfbField_MplsTc{MplsTc: mplsTc}}
285}
286
287func MplsBos(mplsBos uint32) *ofp.OfpOxmOfbField {
288 return &ofp.OfpOxmOfbField{Type: MPLS_BOS, Value: &ofp.OfpOxmOfbField_MplsBos{MplsBos: mplsBos}}
289}
290
291func PbbIsid(pbbIsid uint32) *ofp.OfpOxmOfbField {
292 return &ofp.OfpOxmOfbField{Type: PBB_ISID, Value: &ofp.OfpOxmOfbField_PbbIsid{PbbIsid: pbbIsid}}
293}
294
295func TunnelId(tunnelId uint64) *ofp.OfpOxmOfbField {
296 return &ofp.OfpOxmOfbField{Type: TUNNEL_ID, Value: &ofp.OfpOxmOfbField_TunnelId{TunnelId: tunnelId}}
297}
298
299func Ipv6Exthdr(ipv6Exthdr uint32) *ofp.OfpOxmOfbField {
300 return &ofp.OfpOxmOfbField{Type: IPV6_EXTHDR, Value: &ofp.OfpOxmOfbField_Ipv6Exthdr{Ipv6Exthdr: ipv6Exthdr}}
301}
302
303//frequently used extractors
304
305func excludeAction(action *ofp.OfpAction, exclude ...ofp.OfpActionType) bool {
306 for _, actionToExclude := range exclude {
307 if action.Type == actionToExclude {
308 return true
309 }
310 }
311 return false
312}
313
314func GetActions(flow *ofp.OfpFlowStats, exclude ...ofp.OfpActionType) []*ofp.OfpAction {
315 if flow == nil {
316 return nil
317 }
318 for _, instruction := range flow.Instructions {
319 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
320 instActions := instruction.GetActions()
321 if instActions == nil {
322 return nil
323 }
324 if len(exclude) == 0 {
325 return instActions.Actions
326 } else {
327 filteredAction := make([]*ofp.OfpAction, 0)
328 for _, action := range instActions.Actions {
329 if !excludeAction(action, exclude...) {
330 filteredAction = append(filteredAction, action)
331 }
332 }
333 return filteredAction
334 }
335 }
336 }
337 return nil
338}
339
340func UpdateOutputPortByActionType(flow *ofp.OfpFlowStats, actionType uint32, toPort uint32) *ofp.OfpFlowStats {
341 if flow == nil {
342 return nil
343 }
344 nFlow := (proto.Clone(flow)).(*ofp.OfpFlowStats)
345 nFlow.Instructions = nil
346 nInsts := make([]*ofp.OfpInstruction, 0)
347 for _, instruction := range flow.Instructions {
348 if instruction.Type == actionType {
349 instActions := instruction.GetActions()
350 if instActions == nil {
351 return nil
352 }
353 nActions := make([]*ofp.OfpAction, 0)
354 for _, action := range instActions.Actions {
355 if action.GetOutput() != nil {
356 nActions = append(nActions, Output(toPort))
357 } else {
358 nActions = append(nActions, action)
359 }
360 }
361 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: nActions}}
362 nInsts = append(nInsts, &ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction})
363 } else {
364 nInsts = append(nInsts, instruction)
365 }
366 }
367 nFlow.Instructions = nInsts
368 return nFlow
369}
370
371func excludeOxmOfbField(field *ofp.OfpOxmOfbField, exclude ...ofp.OxmOfbFieldTypes) bool {
372 for _, fieldToExclude := range exclude {
373 if field.Type == fieldToExclude {
374 return true
375 }
376 }
377 return false
378}
379
380func GetOfbFields(flow *ofp.OfpFlowStats, exclude ...ofp.OxmOfbFieldTypes) []*ofp.OfpOxmOfbField {
381 if flow == nil || flow.Match == nil || flow.Match.Type != ofp.OfpMatchType_OFPMT_OXM {
382 return nil
383 }
384 ofbFields := make([]*ofp.OfpOxmOfbField, 0)
385 for _, field := range flow.Match.OxmFields {
386 if field.OxmClass == ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
387 ofbFields = append(ofbFields, field.GetOfbField())
388 }
389 }
390 if len(exclude) == 0 {
391 return ofbFields
392 } else {
393 filteredFields := make([]*ofp.OfpOxmOfbField, 0)
394 for _, ofbField := range ofbFields {
395 if !excludeOxmOfbField(ofbField, exclude...) {
396 filteredFields = append(filteredFields, ofbField)
397 }
398 }
399 return filteredFields
400 }
401}
402
403func GetPacketOutPort(packet *ofp.OfpPacketOut) uint32 {
404 if packet == nil {
405 return 0
406 }
407 for _, action := range packet.GetActions() {
408 if action.Type == OUTPUT {
409 return action.GetOutput().Port
410 }
411 }
412 return 0
413}
414
415func GetOutPort(flow *ofp.OfpFlowStats) uint32 {
416 if flow == nil {
417 return 0
418 }
419 for _, action := range GetActions(flow) {
420 if action.Type == OUTPUT {
421 out := action.GetOutput()
422 if out == nil {
423 return 0
424 }
425 return out.GetPort()
426 }
427 }
428 return 0
429}
430
431func GetInPort(flow *ofp.OfpFlowStats) uint32 {
432 if flow == nil {
433 return 0
434 }
435 for _, field := range GetOfbFields(flow) {
436 if field.Type == IN_PORT {
437 return field.GetPort()
438 }
439 }
440 return 0
441}
442
443func GetGotoTableId(flow *ofp.OfpFlowStats) uint32 {
444 if flow == nil {
445 return 0
446 }
447 for _, instruction := range flow.Instructions {
448 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE) {
449 gotoTable := instruction.GetGotoTable()
450 if gotoTable == nil {
451 return 0
452 }
453 return gotoTable.GetTableId()
454 }
455 }
456 return 0
457}
458
459func GetTunnelId(flow *ofp.OfpFlowStats) uint64 {
460 if flow == nil {
461 return 0
462 }
463 for _, field := range GetOfbFields(flow) {
464 if field.Type == TUNNEL_ID {
465 return field.GetTunnelId()
466 }
467 }
468 return 0
469}
470
471//GetMetaData - legacy get method (only want lower 32 bits)
472func GetMetaData(flow *ofp.OfpFlowStats) uint32 {
473 if flow == nil {
474 return 0
475 }
476 for _, field := range GetOfbFields(flow) {
477 if field.Type == METADATA {
478 return uint32(field.GetTableMetadata() & 0xffffffff)
479 }
480 }
481 return 0
482}
483
484func GetMetaData64Bit(flow *ofp.OfpFlowStats) uint64 {
485 if flow == nil {
486 return 0
487 }
488 for _, field := range GetOfbFields(flow) {
489 if field.Type == METADATA {
490 return field.GetTableMetadata()
491 }
492 }
493 return 0
494}
495
496// GetPortNumberFromMetadata retrieves the port number from the Metadata_ofp. The port number (UNI on ONU) is in the
497// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
498// a Metadata_ofp field
499func GetPortNumberFromMetadata(flow *ofp.OfpFlowStats) uint64 {
500 md := GetMetaData64Bit(flow)
501 if md == 0 {
502 return 0
503 }
504 if md <= 0xffffffff {
505 log.Debugw("onos-upgrade-suggested", log.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
506 return md
507 }
508 return md & 0xffffffff
509}
510
511//GetInnerTagFromMetaData retrieves the inner tag from the Metadata_ofp. The port number (UNI on ONU) is in the
512// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
513//// a Metadata_ofp field
514func GetInnerTagFromMetaData(flow *ofp.OfpFlowStats) uint64 {
515 md := GetMetaData64Bit(flow)
516 if md == 0 {
517 return 0
518 }
519 if md <= 0xffffffff {
520 log.Debugw("onos-upgrade-suggested", log.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
521 return md
522 }
523 return (md >> 32) & 0xffffffff
524}
525
526// Extract the child device port from a flow that contains the parent device peer port. Typically the UNI port of an
527// ONU child device. Per TST agreement this will be the lower 32 bits of tunnel id reserving upper 32 bits for later
528// use
529func GetChildPortFromTunnelId(flow *ofp.OfpFlowStats) uint32 {
530 tid := GetTunnelId(flow)
531 if tid == 0 {
532 return 0
533 }
534 // Per TST agreement we are keeping any child port id (uni port id) in the lower 32 bits
535 return uint32(tid & 0xffffffff)
536}
537
538func HasNextTable(flow *ofp.OfpFlowStats) bool {
539 if flow == nil {
540 return false
541 }
542 return GetGotoTableId(flow) != 0
543}
544
545func GetGroup(flow *ofp.OfpFlowStats) uint32 {
546 if flow == nil {
547 return 0
548 }
549 for _, action := range GetActions(flow) {
550 if action.Type == GROUP {
551 grp := action.GetGroup()
552 if grp == nil {
553 return 0
554 }
555 return grp.GetGroupId()
556 }
557 }
558 return 0
559}
560
561func HasGroup(flow *ofp.OfpFlowStats) bool {
562 return GetGroup(flow) != 0
563}
564
565// GetNextTableId returns the next table ID if the "table_id" is present in the map, otherwise return nil
566func GetNextTableId(kw OfpFlowModArgs) *uint32 {
567 if val, exist := kw["table_id"]; exist {
568 ret := uint32(val)
569 return &ret
570 }
571 return nil
572}
573
574// Return unique 64-bit integer hash for flow covering the following attributes:
575// 'table_id', 'priority', 'flags', 'cookie', 'match', '_instruction_string'
576func HashFlowStats(flow *ofp.OfpFlowStats) uint64 {
577 if flow == nil { // Should never happen
578 return 0
579 }
580 // Create string with the instructions field first
581 var instructionString bytes.Buffer
582 for _, instruction := range flow.Instructions {
583 instructionString.WriteString(instruction.String())
584 }
585 var flowString = fmt.Sprintf("%d%d%d%d%s%s", flow.TableId, flow.Priority, flow.Flags, flow.Cookie, flow.Match.String(), instructionString.String())
586 h := md5.New()
587 h.Write([]byte(flowString))
588 hash := big.NewInt(0)
589 hash.SetBytes(h.Sum(nil))
590 return hash.Uint64()
591}
592
593// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
594func FlowStatsEntryFromFlowModMessage(mod *ofp.OfpFlowMod) *ofp.OfpFlowStats {
595 flow := &ofp.OfpFlowStats{}
596 if mod == nil {
597 return flow
598 }
599 flow.TableId = mod.TableId
600 flow.Priority = mod.Priority
601 flow.IdleTimeout = mod.IdleTimeout
602 flow.HardTimeout = mod.HardTimeout
603 flow.Flags = mod.Flags
604 flow.Cookie = mod.Cookie
605 flow.Match = mod.Match
606 flow.Instructions = mod.Instructions
607 flow.Id = HashFlowStats(flow)
608 return flow
609}
610
611func GroupEntryFromGroupMod(mod *ofp.OfpGroupMod) *ofp.OfpGroupEntry {
612 group := &ofp.OfpGroupEntry{}
613 if mod == nil {
614 return group
615 }
616 group.Desc = &ofp.OfpGroupDesc{Type: mod.Type, GroupId: mod.GroupId, Buckets: mod.Buckets}
617 group.Stats = &ofp.OfpGroupStats{GroupId: mod.GroupId}
618 //TODO do we need to instantiate bucket bins?
619 return group
620}
621
622func MkOxmFields(matchFields []ofp.OfpOxmField) []*ofp.OfpOxmField {
623 oxmFields := make([]*ofp.OfpOxmField, 0)
624 for _, matchField := range matchFields {
625 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
626 oxmFields = append(oxmFields, &oxmField)
627 }
628 return oxmFields
629}
630
631func MkInstructionsFromActions(actions []*ofp.OfpAction) []*ofp.OfpInstruction {
632 instructions := make([]*ofp.OfpInstruction, 0)
633 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
634 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
635 instructions = append(instructions, &instruction)
636 return instructions
637}
638
639// Convenience function to generare ofp_flow_mod message with OXM BASIC match composed from the match_fields, and
640// single APPLY_ACTIONS instruction with a list if ofp_action objects.
641func MkSimpleFlowMod(matchFields []*ofp.OfpOxmField, actions []*ofp.OfpAction, command *ofp.OfpFlowModCommand, kw OfpFlowModArgs) *ofp.OfpFlowMod {
642
643 // Process actions instructions
644 instructions := make([]*ofp.OfpInstruction, 0)
645 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
646 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
647 instructions = append(instructions, &instruction)
648
649 // Process next table
650 if tableId := GetNextTableId(kw); tableId != nil {
651 var instGotoTable ofp.OfpInstruction_GotoTable
652 instGotoTable.GotoTable = &ofp.OfpInstructionGotoTable{TableId: *tableId}
653 inst := ofp.OfpInstruction{Type: uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE), Data: &instGotoTable}
654 instructions = append(instructions, &inst)
655 }
656
657 // Process match fields
658 oxmFields := make([]*ofp.OfpOxmField, 0)
659 for _, matchField := range matchFields {
660 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
661 oxmFields = append(oxmFields, &oxmField)
662 }
663 var match ofp.OfpMatch
664 match.Type = ofp.OfpMatchType_OFPMT_OXM
665 match.OxmFields = oxmFields
666
667 // Create ofp_flow_message
668 msg := &ofp.OfpFlowMod{}
669 if command == nil {
670 msg.Command = ofp.OfpFlowModCommand_OFPFC_ADD
671 } else {
672 msg.Command = *command
673 }
674 msg.Instructions = instructions
675 msg.Match = &match
676
677 // Set the variadic argument values
678 msg = setVariadicModAttributes(msg, kw)
679
680 return msg
681}
682
683func MkMulticastGroupMod(groupId uint32, buckets []*ofp.OfpBucket, command *ofp.OfpGroupModCommand) *ofp.OfpGroupMod {
684 group := &ofp.OfpGroupMod{}
685 if command == nil {
686 group.Command = ofp.OfpGroupModCommand_OFPGC_ADD
687 } else {
688 group.Command = *command
689 }
690 group.Type = ofp.OfpGroupType_OFPGT_ALL
691 group.GroupId = groupId
692 group.Buckets = buckets
693 return group
694}
695
696//SetVariadicModAttributes sets only uint64 or uint32 fields of the ofp_flow_mod message
697func setVariadicModAttributes(mod *ofp.OfpFlowMod, args OfpFlowModArgs) *ofp.OfpFlowMod {
698 if args == nil {
699 return mod
700 }
701 for key, val := range args {
702 switch key {
703 case "cookie":
704 mod.Cookie = val
705 case "cookie_mask":
706 mod.CookieMask = val
707 case "table_id":
708 mod.TableId = uint32(val)
709 case "idle_timeout":
710 mod.IdleTimeout = uint32(val)
711 case "hard_timeout":
712 mod.HardTimeout = uint32(val)
713 case "priority":
714 mod.Priority = uint32(val)
715 case "buffer_id":
716 mod.BufferId = uint32(val)
717 case "out_port":
718 mod.OutPort = uint32(val)
719 case "out_group":
720 mod.OutGroup = uint32(val)
721 case "flags":
722 mod.Flags = uint32(val)
723 }
724 }
725 return mod
726}
727
728func MkPacketIn(port uint32, packet []byte) *ofp.OfpPacketIn {
729 packetIn := &ofp.OfpPacketIn{
730 Reason: ofp.OfpPacketInReason_OFPR_ACTION,
731 Match: &ofp.OfpMatch{
732 Type: ofp.OfpMatchType_OFPMT_OXM,
733 OxmFields: []*ofp.OfpOxmField{
734 {
735 OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
736 Field: &ofp.OfpOxmField_OfbField{
737 OfbField: InPort(port)},
738 },
739 },
740 },
741 Data: packet,
742 }
743 return packetIn
744}
745
746// MkFlowStat is a helper method to build flows
747func MkFlowStat(fa *FlowArgs) *ofp.OfpFlowStats {
748 //Build the matchfields
749 matchFields := make([]*ofp.OfpOxmField, 0)
750 for _, val := range fa.MatchFields {
751 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
752 }
753 return FlowStatsEntryFromFlowModMessage(MkSimpleFlowMod(matchFields, fa.Actions, fa.Command, fa.KV))
754}
755
756func MkGroupStat(ga *GroupArgs) *ofp.OfpGroupEntry {
757 return GroupEntryFromGroupMod(MkMulticastGroupMod(ga.GroupId, ga.Buckets, ga.Command))
758}
759
khenaidoo89b0e942018-10-21 21:11:33 -0400760type OfpFlowModArgs map[string]uint64
761
762type FlowArgs struct {
763 MatchFields []*ofp.OfpOxmOfbField
764 Actions []*ofp.OfpAction
765 Command *ofp.OfpFlowModCommand
766 Priority uint32
767 KV OfpFlowModArgs
768}
769
khenaidood20a5852018-10-22 22:09:55 -0400770type GroupArgs struct {
771 GroupId uint32
772 Buckets []*ofp.OfpBucket
773 Command *ofp.OfpGroupModCommand
774}
775
khenaidoo89b0e942018-10-21 21:11:33 -0400776type FlowsAndGroups struct {
777 Flows *ordered_map.OrderedMap
778 Groups *ordered_map.OrderedMap
779}
780
781func NewFlowsAndGroups() *FlowsAndGroups {
782 var fg FlowsAndGroups
783 fg.Flows = ordered_map.NewOrderedMap()
784 fg.Groups = ordered_map.NewOrderedMap()
785 return &fg
786}
787
788func (fg *FlowsAndGroups) Copy() *FlowsAndGroups {
789 copyFG := NewFlowsAndGroups()
790 iter := fg.Flows.IterFunc()
791 for kv, ok := iter(); ok; kv, ok = iter() {
792 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
793 copyFG.Flows.Set(kv.Key, proto.Clone(protoMsg))
794 }
795 }
796 iter = fg.Groups.IterFunc()
797 for kv, ok := iter(); ok; kv, ok = iter() {
798 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
799 copyFG.Groups.Set(kv.Key, proto.Clone(protoMsg))
800 }
801 }
802 return copyFG
803}
804
805func (fg *FlowsAndGroups) GetFlow(index int) *ofp.OfpFlowStats {
806 iter := fg.Flows.IterFunc()
807 pos := 0
808 for kv, ok := iter(); ok; kv, ok = iter() {
809 if pos == index {
810 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
811 return protoMsg
812 }
813 return nil
814 }
815 pos += 1
816 }
817 return nil
818}
819
khenaidoo19d7b632018-10-30 10:49:50 -0400820func (fg *FlowsAndGroups) ListFlows() []*ofp.OfpFlowStats {
821 flows := make([]*ofp.OfpFlowStats, 0)
822 iter := fg.Flows.IterFunc()
823 for kv, ok := iter(); ok; kv, ok = iter() {
824 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
825 flows = append(flows, protoMsg)
826 }
827 }
828 return flows
829}
830
831func (fg *FlowsAndGroups) ListGroups() []*ofp.OfpGroupEntry {
832 groups := make([]*ofp.OfpGroupEntry, 0)
833 iter := fg.Groups.IterFunc()
834 for kv, ok := iter(); ok; kv, ok = iter() {
835 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
836 groups = append(groups, protoMsg)
837 }
838 }
839 return groups
840}
841
khenaidoo89b0e942018-10-21 21:11:33 -0400842func (fg *FlowsAndGroups) String() string {
843 var buffer bytes.Buffer
844 iter := fg.Flows.IterFunc()
845 for kv, ok := iter(); ok; kv, ok = iter() {
846 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
847 buffer.WriteString("\nFlow:\n")
848 buffer.WriteString(proto.MarshalTextString(protoMsg))
849 buffer.WriteString("\n")
850 }
851 }
852 iter = fg.Groups.IterFunc()
853 for kv, ok := iter(); ok; kv, ok = iter() {
854 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
855 buffer.WriteString("\nGroup:\n")
856 buffer.WriteString(proto.MarshalTextString(protoMsg))
857 buffer.WriteString("\n")
858 }
859 }
860 return buffer.String()
861}
862
863func (fg *FlowsAndGroups) AddFlow(flow *ofp.OfpFlowStats) {
khenaidoo68c930b2019-05-13 11:46:51 -0400864 if flow == nil {
865 return
866 }
867
khenaidoo89b0e942018-10-21 21:11:33 -0400868 if fg.Flows == nil {
869 fg.Flows = ordered_map.NewOrderedMap()
870 }
871 if fg.Groups == nil {
872 fg.Groups = ordered_map.NewOrderedMap()
873 }
874 //Add flow only if absent
875 if _, exist := fg.Flows.Get(flow.Id); !exist {
876 fg.Flows.Set(flow.Id, flow)
877 }
878}
879
khenaidoo68c930b2019-05-13 11:46:51 -0400880func (fg *FlowsAndGroups) AddGroup(group *ofp.OfpGroupEntry) {
881 if group == nil {
882 return
883 }
884
885 if fg.Flows == nil {
886 fg.Flows = ordered_map.NewOrderedMap()
887 }
888 if fg.Groups == nil {
889 fg.Groups = ordered_map.NewOrderedMap()
890 }
891 //Add group only if absent
892 if _, exist := fg.Groups.Get(group.Desc.GroupId); !exist {
893 fg.Groups.Set(group.Desc.GroupId, group)
894 }
895}
896
khenaidoo89b0e942018-10-21 21:11:33 -0400897//AddFrom add flows and groups from the argument into this structure only if they do not already exist
898func (fg *FlowsAndGroups) AddFrom(from *FlowsAndGroups) {
899 iter := from.Flows.IterFunc()
900 for kv, ok := iter(); ok; kv, ok = iter() {
901 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
902 if _, exist := fg.Flows.Get(protoMsg.Id); !exist {
903 fg.Flows.Set(protoMsg.Id, protoMsg)
904 }
905 }
906 }
907 iter = from.Groups.IterFunc()
908 for kv, ok := iter(); ok; kv, ok = iter() {
909 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
910 if _, exist := fg.Groups.Get(protoMsg.Stats.GroupId); !exist {
911 fg.Groups.Set(protoMsg.Stats.GroupId, protoMsg)
912 }
913 }
914 }
915}
916
917type DeviceRules struct {
918 Rules map[string]*FlowsAndGroups
919}
920
921func NewDeviceRules() *DeviceRules {
922 var dr DeviceRules
923 dr.Rules = make(map[string]*FlowsAndGroups)
924 return &dr
925}
926
927func (dr *DeviceRules) Copy() *DeviceRules {
928 copyDR := NewDeviceRules()
manikkaraj k6c9689d2019-05-09 12:59:52 -0400929 if dr != nil {
930 for key, val := range dr.Rules {
931 if val != nil {
932 copyDR.Rules[key] = val.Copy()
933 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400934 }
khenaidoo89b0e942018-10-21 21:11:33 -0400935 }
936 return copyDR
937}
938
khenaidoo19d7b632018-10-30 10:49:50 -0400939func (dr *DeviceRules) ClearFlows(deviceId string) {
940 if _, exist := dr.Rules[deviceId]; exist {
941 dr.Rules[deviceId].Flows = ordered_map.NewOrderedMap()
942 }
943}
944
khenaidoo2c6a0992019-04-29 13:46:56 -0400945func (dr *DeviceRules) FilterRules(deviceIds map[string]string) *DeviceRules {
946 filteredDR := NewDeviceRules()
947 for key, val := range dr.Rules {
948 if _, exist := deviceIds[key]; exist {
949 filteredDR.Rules[key] = val.Copy()
950 }
951 }
952 return filteredDR
953}
954
khenaidoo19d7b632018-10-30 10:49:50 -0400955func (dr *DeviceRules) AddFlow(deviceId string, flow *ofp.OfpFlowStats) {
956 if _, exist := dr.Rules[deviceId]; !exist {
957 dr.Rules[deviceId] = NewFlowsAndGroups()
958 }
959 dr.Rules[deviceId].AddFlow(flow)
960}
961
962func (dr *DeviceRules) GetRules() map[string]*FlowsAndGroups {
963 return dr.Rules
964}
965
khenaidoo89b0e942018-10-21 21:11:33 -0400966func (dr *DeviceRules) String() string {
967 var buffer bytes.Buffer
968 for key, value := range dr.Rules {
969 buffer.WriteString("DeviceId:")
970 buffer.WriteString(key)
971 buffer.WriteString(value.String())
972 buffer.WriteString("\n\n")
973 }
974 return buffer.String()
975}
976
977func (dr *DeviceRules) AddFlowsAndGroup(deviceId string, fg *FlowsAndGroups) {
khenaidood20a5852018-10-22 22:09:55 -0400978 if _, ok := dr.Rules[deviceId]; !ok {
979 dr.Rules[deviceId] = NewFlowsAndGroups()
980 }
khenaidoo89b0e942018-10-21 21:11:33 -0400981 dr.Rules[deviceId] = fg
982}
khenaidood20a5852018-10-22 22:09:55 -0400983
984// CreateEntryIfNotExist creates a new deviceId in the Map if it does not exist and assigns an
985// empty FlowsAndGroups to it. Otherwise, it does nothing.
986func (dr *DeviceRules) CreateEntryIfNotExist(deviceId string) {
987 if _, ok := dr.Rules[deviceId]; !ok {
988 dr.Rules[deviceId] = NewFlowsAndGroups()
989 }
990}
khenaidoo19d7b632018-10-30 10:49:50 -0400991
992/*
993 * Common flow routines
994 */
995
996//FindOverlappingFlows return a list of overlapping flow(s) where mod is the flow request
997func FindOverlappingFlows(flows []*ofp.OfpFlowStats, mod *ofp.OfpFlowMod) []*ofp.OfpFlowStats {
998 return nil //TODO - complete implementation
999}
1000
1001// FindFlowById returns the index of the flow in the flows array if present. Otherwise, it returns -1
1002func FindFlowById(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
1003 for idx, f := range flows {
1004 if flow.Id == f.Id {
1005 return idx
1006 }
1007 }
1008 return -1
1009}
1010
1011// FindFlows returns the index in flows where flow if present. Otherwise, it returns -1
1012func FindFlows(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
1013 for idx, f := range flows {
1014 if FlowMatch(f, flow) {
1015 return idx
1016 }
1017 }
1018 return -1
1019}
1020
1021//FlowMatch returns true if two flows matches on the following flow attributes:
1022//TableId, Priority, Flags, Cookie, Match
1023func FlowMatch(f1 *ofp.OfpFlowStats, f2 *ofp.OfpFlowStats) bool {
khenaidoo68c930b2019-05-13 11:46:51 -04001024 if f1 == nil || f2 == nil {
1025 return false
1026 }
khenaidoo19d7b632018-10-30 10:49:50 -04001027 keysMatter := []string{"TableId", "Priority", "Flags", "Cookie", "Match"}
1028 for _, key := range keysMatter {
1029 switch key {
1030 case "TableId":
1031 if f1.TableId != f2.TableId {
1032 return false
1033 }
1034 case "Priority":
1035 if f1.Priority != f2.Priority {
1036 return false
1037 }
1038 case "Flags":
1039 if f1.Flags != f2.Flags {
1040 return false
1041 }
1042 case "Cookie":
1043 if f1.Cookie != f2.Cookie {
1044 return false
1045 }
1046 case "Match":
1047 if strings.Compare(f1.Match.String(), f2.Match.String()) != 0 {
1048 return false
1049 }
1050 }
1051 }
1052 return true
1053}
1054
1055//FlowMatchesMod returns True if given flow is "covered" by the wildcard flow_mod, taking into consideration of
1056//both exact matches as well as masks-based match fields if any. Otherwise return False
1057func FlowMatchesMod(flow *ofp.OfpFlowStats, mod *ofp.OfpFlowMod) bool {
khenaidoo68c930b2019-05-13 11:46:51 -04001058 if flow == nil || mod == nil {
1059 return false
1060 }
khenaidoo19d7b632018-10-30 10:49:50 -04001061 //Check if flow.cookie is covered by mod.cookie and mod.cookie_mask
1062 if (flow.Cookie & mod.CookieMask) != (mod.Cookie & mod.CookieMask) {
1063 return false
1064 }
1065
1066 //Check if flow.table_id is covered by flow_mod.table_id
1067 if mod.TableId != uint32(ofp.OfpTable_OFPTT_ALL) && flow.TableId != mod.TableId {
1068 return false
1069 }
1070
1071 //Check out_port
1072 if (mod.OutPort&0x7fffffff) != uint32(ofp.OfpPortNo_OFPP_ANY) && !FlowHasOutPort(flow, mod.OutPort) {
1073 return false
1074 }
1075
1076 // Check out_group
1077 if (mod.OutGroup&0x7fffffff) != uint32(ofp.OfpGroup_OFPG_ANY) && !FlowHasOutGroup(flow, mod.OutGroup) {
1078 return false
1079 }
1080
1081 //Priority is ignored
1082
1083 //Check match condition
1084 //If the flow_mod match field is empty, that is a special case and indicates the flow entry matches
khenaidoo0458db62019-06-20 08:50:36 -04001085 if (mod.Match == nil) || (mod.Match.OxmFields == nil) || (len(mod.Match.OxmFields) == 0) {
khenaidoo19d7b632018-10-30 10:49:50 -04001086 //If we got this far and the match is empty in the flow spec, than the flow matches
1087 return true
1088 } // TODO : implement the flow match analysis
1089 return false
1090
1091}
1092
1093//FlowHasOutPort returns True if flow has a output command with the given out_port
1094func FlowHasOutPort(flow *ofp.OfpFlowStats, outPort uint32) bool {
khenaidoo68c930b2019-05-13 11:46:51 -04001095 if flow == nil {
1096 return false
1097 }
khenaidoo19d7b632018-10-30 10:49:50 -04001098 for _, instruction := range flow.Instructions {
1099 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
1100 if instruction.GetActions() == nil {
1101 return false
1102 }
1103 for _, action := range instruction.GetActions().Actions {
1104 if action.Type == ofp.OfpActionType_OFPAT_OUTPUT {
1105 if (action.GetOutput() != nil) && (action.GetOutput().Port == outPort) {
1106 return true
1107 }
1108 }
1109
1110 }
1111 }
1112 }
1113 return false
1114}
1115
1116//FlowHasOutGroup return True if flow has a output command with the given out_group
1117func FlowHasOutGroup(flow *ofp.OfpFlowStats, groupID uint32) bool {
khenaidoo68c930b2019-05-13 11:46:51 -04001118 if flow == nil {
1119 return false
1120 }
khenaidoo19d7b632018-10-30 10:49:50 -04001121 for _, instruction := range flow.Instructions {
1122 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
1123 if instruction.GetActions() == nil {
1124 return false
1125 }
1126 for _, action := range instruction.GetActions().Actions {
1127 if action.Type == ofp.OfpActionType_OFPAT_GROUP {
1128 if (action.GetGroup() != nil) && (action.GetGroup().GroupId == groupID) {
1129 return true
1130 }
1131 }
1132
1133 }
1134 }
1135 }
1136 return false
1137}
1138
1139//FindGroup returns index of group if found, else returns -1
1140func FindGroup(groups []*ofp.OfpGroupEntry, groupId uint32) int {
1141 for idx, group := range groups {
1142 if group.Desc.GroupId == groupId {
1143 return idx
1144 }
1145 }
1146 return -1
1147}
1148
1149func FlowsDeleteByGroupId(flows []*ofp.OfpFlowStats, groupId uint32) (bool, []*ofp.OfpFlowStats) {
1150 toKeep := make([]*ofp.OfpFlowStats, 0)
1151
1152 for _, f := range flows {
1153 if !FlowHasOutGroup(f, groupId) {
1154 toKeep = append(toKeep, f)
1155 }
1156 }
1157 return len(toKeep) < len(flows), toKeep
1158}
khenaidoo0458db62019-06-20 08:50:36 -04001159
1160func ToOfpOxmField(from []*ofp.OfpOxmOfbField) []*ofp.OfpOxmField {
1161 matchFields := make([]*ofp.OfpOxmField, 0)
1162 for _, val := range from {
1163 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
1164 }
1165 return matchFields
1166}