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