blob: 9a9448f02a41587c379a3d3a1163f15d9cdc5fa9 [file] [log] [blame]
Matt Jeanneretcab955f2019-04-10 15:45:57 -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 Baker355d1742019-10-24 10:57:52 -070016package flows
Matt Jeanneretcab955f2019-04-10 15:45:57 -040017
18import (
19 "bytes"
Neha Sharma96b7bf22020-06-15 10:37:32 +000020 "context"
Matt Jeannereta93dbed2019-05-17 12:40:05 -040021 "crypto/md5"
Girish Gowdraf369c0a2020-05-15 13:27:38 -070022 "encoding/binary"
Matt Jeannereta93dbed2019-05-17 12:40:05 -040023 "fmt"
Girish Gowdraf369c0a2020-05-15 13:27:38 -070024 "hash"
25 "sort"
26
Matt Jeanneretcab955f2019-04-10 15:45:57 -040027 "github.com/cevaris/ordered_map"
28 "github.com/gogo/protobuf/proto"
Girish Gowdra4c3d4602021-07-22 16:33:37 -070029 "github.com/opencord/voltha-lib-go/v6/pkg/log"
Girish Gowdraa09aeab2020-09-14 16:30:52 -070030 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
Matt Jeanneretcab955f2019-04-10 15:45:57 -040031)
32
Matt Jeannereta93dbed2019-05-17 12:40:05 -040033var (
34 // Instructions shortcut
Manikkaraj kb1d51442019-07-23 10:41:02 -040035 APPLY_ACTIONS = ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS
36 WRITE_METADATA = ofp.OfpInstructionType_OFPIT_WRITE_METADATA
37 METER_ACTION = ofp.OfpInstructionType_OFPIT_METER
Matt Jeannereta93dbed2019-05-17 12:40:05 -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 kb1d51442019-07-23 10:41:02 -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
Scott Baker355d1742019-10-24 10:57:52 -0700480func 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
Girish Gowdraa09aeab2020-09-14 16:30:52 -0700494func GetSetActionField(ctx context.Context, flow *ofp.OfpFlowStats, ofbType ofp.OxmOfbFieldTypes) (uint32, bool) {
495 if flow == nil {
496 return 0, false
497 }
498 for _, instruction := range flow.Instructions {
499 if instruction.Type == uint32(APPLY_ACTIONS) {
500 actions := instruction.GetActions()
501 for _, action := range actions.GetActions() {
502 if action.Type == SET_FIELD {
503 setField := action.GetSetField()
504 if setField.Field.GetOfbField().Type == ofbType {
505 switch ofbType {
506 case VLAN_PCP:
507 return setField.Field.GetOfbField().GetVlanPcp(), true
508 case VLAN_VID:
509 return setField.Field.GetOfbField().GetVlanVid(), true
510 default:
511 logger.Errorw(ctx, "unsupported-ofb-field-type", log.Fields{"ofbType": ofbType})
512 return 0, false
513 }
514 }
515 }
516 }
517 return 0, false
518 }
519 }
520 return 0, false
521}
522
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400523func GetTunnelId(flow *ofp.OfpFlowStats) uint64 {
524 if flow == nil {
525 return 0
526 }
527 for _, field := range GetOfbFields(flow) {
528 if field.Type == TUNNEL_ID {
529 return field.GetTunnelId()
530 }
531 }
532 return 0
533}
534
535//GetMetaData - legacy get method (only want lower 32 bits)
Neha Sharma96b7bf22020-06-15 10:37:32 +0000536func GetMetaData(ctx context.Context, flow *ofp.OfpFlowStats) uint32 {
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400537 if flow == nil {
538 return 0
539 }
540 for _, field := range GetOfbFields(flow) {
541 if field.Type == METADATA {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400542 return uint32(field.GetTableMetadata() & 0xFFFFFFFF)
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400543 }
544 }
Neha Sharma96b7bf22020-06-15 10:37:32 +0000545 logger.Debug(ctx, "No-metadata-present")
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400546 return 0
547}
548
Neha Sharma96b7bf22020-06-15 10:37:32 +0000549func GetMetaData64Bit(ctx context.Context, flow *ofp.OfpFlowStats) uint64 {
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400550 if flow == nil {
551 return 0
552 }
553 for _, field := range GetOfbFields(flow) {
554 if field.Type == METADATA {
555 return field.GetTableMetadata()
556 }
557 }
Neha Sharma96b7bf22020-06-15 10:37:32 +0000558 logger.Debug(ctx, "No-metadata-present")
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400559 return 0
560}
561
Manikkaraj kb1d51442019-07-23 10:41:02 -0400562// function returns write metadata value from write_metadata action field
Neha Sharma96b7bf22020-06-15 10:37:32 +0000563func GetMetadataFromWriteMetadataAction(ctx context.Context, flow *ofp.OfpFlowStats) uint64 {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400564 if flow != nil {
565 for _, instruction := range flow.Instructions {
566 if instruction.Type == uint32(WRITE_METADATA) {
567 if writeMetadata := instruction.GetWriteMetadata(); writeMetadata != nil {
568 return writeMetadata.GetMetadata()
569 }
570 }
571 }
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400572 }
Neha Sharma96b7bf22020-06-15 10:37:32 +0000573 logger.Debugw(ctx, "No-write-metadata-present", log.Fields{"flow": flow})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400574 return 0
575}
576
Neha Sharma96b7bf22020-06-15 10:37:32 +0000577func GetTechProfileIDFromWriteMetaData(ctx context.Context, metadata uint64) uint16 {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400578 /*
579 Write metadata instruction value (metadata) is 8 bytes:
580 MS 2 bytes: C Tag
581 Next 2 bytes: Technology Profile Id
582 Next 4 bytes: Port number (uni or nni)
583
584 This is set in the ONOS OltPipeline as a write metadata instruction
585 */
586 var tpId uint16 = 0
Neha Sharma96b7bf22020-06-15 10:37:32 +0000587 logger.Debugw(ctx, "Write metadata value for Techprofile ID", log.Fields{"metadata": metadata})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400588 if metadata != 0 {
589 tpId = uint16((metadata >> 32) & 0xFFFF)
Neha Sharma96b7bf22020-06-15 10:37:32 +0000590 logger.Debugw(ctx, "Found techprofile ID from write metadata action", log.Fields{"tpid": tpId})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400591 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400592 return tpId
593}
594
Neha Sharma96b7bf22020-06-15 10:37:32 +0000595func GetEgressPortNumberFromWriteMetadata(ctx context.Context, flow *ofp.OfpFlowStats) uint32 {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400596 /*
597 Write metadata instruction value (metadata) is 8 bytes:
598 MS 2 bytes: C Tag
599 Next 2 bytes: Technology Profile Id
600 Next 4 bytes: Port number (uni or nni)
601 This is set in the ONOS OltPipeline as a write metadata instruction
602 */
603 var uniPort uint32 = 0
Neha Sharma96b7bf22020-06-15 10:37:32 +0000604 md := GetMetadataFromWriteMetadataAction(ctx, flow)
605 logger.Debugw(ctx, "Metadata found for egress/uni port ", log.Fields{"metadata": md})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400606 if md != 0 {
607 uniPort = uint32(md & 0xFFFFFFFF)
Neha Sharma96b7bf22020-06-15 10:37:32 +0000608 logger.Debugw(ctx, "Found EgressPort from write metadata action", log.Fields{"egress_port": uniPort})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400609 }
610 return uniPort
611
612}
613
Neha Sharma96b7bf22020-06-15 10:37:32 +0000614func GetInnerTagFromMetaData(ctx context.Context, flow *ofp.OfpFlowStats) uint16 {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400615 /*
616 Write metadata instruction value (metadata) is 8 bytes:
617 MS 2 bytes: C Tag
618 Next 2 bytes: Technology Profile Id
619 Next 4 bytes: Port number (uni or nni)
620 This is set in the ONOS OltPipeline as a write metadata instruction
621 */
622 var innerTag uint16 = 0
Neha Sharma96b7bf22020-06-15 10:37:32 +0000623 md := GetMetadataFromWriteMetadataAction(ctx, flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400624 if md != 0 {
625 innerTag = uint16((md >> 48) & 0xFFFF)
Neha Sharma96b7bf22020-06-15 10:37:32 +0000626 logger.Debugw(ctx, "Found CVLAN from write metadate action", log.Fields{"c_vlan": innerTag})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400627 }
628 return innerTag
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400629}
630
631//GetInnerTagFromMetaData retrieves the inner tag from the Metadata_ofp. The port number (UNI on ONU) is in the
632// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
633//// a Metadata_ofp field
Manikkaraj kb1d51442019-07-23 10:41:02 -0400634/*func GetInnerTagFromMetaData(flow *ofp.OfpFlowStats) uint64 {
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400635 md := GetMetaData64Bit(flow)
636 if md == 0 {
637 return 0
638 }
639 if md <= 0xffffffff {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000640 logger.Debugw(ctx, "onos-upgrade-suggested", logger.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400641 return md
642 }
643 return (md >> 32) & 0xffffffff
Manikkaraj kb1d51442019-07-23 10:41:02 -0400644}*/
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400645
646// Extract the child device port from a flow that contains the parent device peer port. Typically the UNI port of an
647// ONU child device. Per TST agreement this will be the lower 32 bits of tunnel id reserving upper 32 bits for later
648// use
649func GetChildPortFromTunnelId(flow *ofp.OfpFlowStats) uint32 {
650 tid := GetTunnelId(flow)
651 if tid == 0 {
652 return 0
653 }
654 // Per TST agreement we are keeping any child port id (uni port id) in the lower 32 bits
655 return uint32(tid & 0xffffffff)
656}
657
658func HasNextTable(flow *ofp.OfpFlowStats) bool {
659 if flow == nil {
660 return false
661 }
662 return GetGotoTableId(flow) != 0
663}
664
665func GetGroup(flow *ofp.OfpFlowStats) uint32 {
666 if flow == nil {
667 return 0
668 }
669 for _, action := range GetActions(flow) {
670 if action.Type == GROUP {
671 grp := action.GetGroup()
672 if grp == nil {
673 return 0
674 }
675 return grp.GetGroupId()
676 }
677 }
678 return 0
679}
680
681func HasGroup(flow *ofp.OfpFlowStats) bool {
682 return GetGroup(flow) != 0
683}
684
685// GetNextTableId returns the next table ID if the "table_id" is present in the map, otherwise return nil
686func GetNextTableId(kw OfpFlowModArgs) *uint32 {
687 if val, exist := kw["table_id"]; exist {
688 ret := uint32(val)
689 return &ret
690 }
691 return nil
692}
693
Manikkaraj kb1d51442019-07-23 10:41:02 -0400694// GetMeterIdFlowModArgs returns the meterId if the "meter_id" is present in the map, otherwise return 0
695func GetMeterIdFlowModArgs(kw OfpFlowModArgs) uint32 {
696 if val, exist := kw["meter_id"]; exist {
697 return uint32(val)
698 }
699 return 0
700}
701
702// Function returns the metadata if the "write_metadata" is present in the map, otherwise return nil
703func GetMetadataFlowModArgs(kw OfpFlowModArgs) uint64 {
704 if val, exist := kw["write_metadata"]; exist {
705 ret := uint64(val)
706 return ret
707 }
708 return 0
709}
710
Girish Gowdraf369c0a2020-05-15 13:27:38 -0700711// HashFlowStats returns a unique 64-bit integer hash of 'table_id', 'priority', and 'match'
712// The OF spec states that:
713// A flow table entry is identified by its match fields and priority: the match fields
714// and priority taken together identify a unique flow entry in the flow table.
divyadesaid26f6b12020-03-19 06:30:28 +0000715func HashFlowStats(flow *ofp.OfpFlowStats) (uint64, error) {
Girish Gowdraf369c0a2020-05-15 13:27:38 -0700716 // first we need to make sure the oxm fields are in a predictable order (the specific order doesn't matter)
717 sort.Slice(flow.Match.OxmFields, func(a, b int) bool {
718 fieldsA, fieldsB := flow.Match.OxmFields[a], flow.Match.OxmFields[b]
719 if fieldsA.OxmClass < fieldsB.OxmClass {
720 return true
721 }
722 switch fieldA := fieldsA.Field.(type) {
723 case *ofp.OfpOxmField_OfbField:
724 switch fieldB := fieldsB.Field.(type) {
725 case *ofp.OfpOxmField_ExperimenterField:
726 return true // ofp < experimenter
727 case *ofp.OfpOxmField_OfbField:
728 return fieldA.OfbField.Type < fieldB.OfbField.Type
729 }
730 case *ofp.OfpOxmField_ExperimenterField:
731 switch fieldB := fieldsB.Field.(type) {
732 case *ofp.OfpOxmField_OfbField:
733 return false // ofp < experimenter
734 case *ofp.OfpOxmField_ExperimenterField:
735 eFieldA, eFieldB := fieldA.ExperimenterField, fieldB.ExperimenterField
736 if eFieldA.Experimenter != eFieldB.Experimenter {
737 return eFieldA.Experimenter < eFieldB.Experimenter
738 }
739 return eFieldA.OxmHeader < eFieldB.OxmHeader
740 }
741 }
742 return false
743 })
744
745 md5Hash := md5.New() // note that write errors will never occur with md5 hashing
746 var tmp [12]byte
747
748 binary.BigEndian.PutUint32(tmp[0:4], flow.TableId) // tableId
749 binary.BigEndian.PutUint32(tmp[4:8], flow.Priority) // priority
750 binary.BigEndian.PutUint32(tmp[8:12], uint32(flow.Match.Type)) // match type
751 _, _ = md5Hash.Write(tmp[:12])
752
753 for _, field := range flow.Match.OxmFields { // for all match fields
754 binary.BigEndian.PutUint32(tmp[:4], uint32(field.OxmClass)) // match class
755 _, _ = md5Hash.Write(tmp[:4])
756
757 switch oxmField := field.Field.(type) {
758 case *ofp.OfpOxmField_ExperimenterField:
759 binary.BigEndian.PutUint32(tmp[0:4], oxmField.ExperimenterField.Experimenter)
760 binary.BigEndian.PutUint32(tmp[4:8], oxmField.ExperimenterField.OxmHeader)
761 _, _ = md5Hash.Write(tmp[:8])
762
763 case *ofp.OfpOxmField_OfbField:
764 if err := hashWriteOfbField(md5Hash, oxmField.OfbField); err != nil {
765 return 0, err
766 }
767
768 default:
769 return 0, fmt.Errorf("unknown OfpOxmField type: %T", field.Field)
770 }
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400771 }
Girish Gowdraf369c0a2020-05-15 13:27:38 -0700772
773 ret := md5Hash.Sum(nil)
774 return binary.BigEndian.Uint64(ret[0:8]), nil
775}
776
777func hashWriteOfbField(md5Hash hash.Hash, field *ofp.OfpOxmOfbField) error {
778 var tmp [8]byte
779 binary.BigEndian.PutUint32(tmp[:4], uint32(field.Type)) // type
780 _, _ = md5Hash.Write(tmp[:4])
781
782 // value
783 valType, val32, val64, valSlice := uint8(0), uint32(0), uint64(0), []byte(nil)
784 switch val := field.Value.(type) {
785 case *ofp.OfpOxmOfbField_Port:
786 valType, val32 = 4, val.Port
787 case *ofp.OfpOxmOfbField_PhysicalPort:
788 valType, val32 = 4, val.PhysicalPort
789 case *ofp.OfpOxmOfbField_TableMetadata:
790 valType, val64 = 8, val.TableMetadata
791 case *ofp.OfpOxmOfbField_EthDst:
792 valType, valSlice = 1, val.EthDst
793 case *ofp.OfpOxmOfbField_EthSrc:
794 valType, valSlice = 1, val.EthSrc
795 case *ofp.OfpOxmOfbField_EthType:
796 valType, val32 = 4, val.EthType
797 case *ofp.OfpOxmOfbField_VlanVid:
798 valType, val32 = 4, val.VlanVid
799 case *ofp.OfpOxmOfbField_VlanPcp:
800 valType, val32 = 4, val.VlanPcp
801 case *ofp.OfpOxmOfbField_IpDscp:
802 valType, val32 = 4, val.IpDscp
803 case *ofp.OfpOxmOfbField_IpEcn:
804 valType, val32 = 4, val.IpEcn
805 case *ofp.OfpOxmOfbField_IpProto:
806 valType, val32 = 4, val.IpProto
807 case *ofp.OfpOxmOfbField_Ipv4Src:
808 valType, val32 = 4, val.Ipv4Src
809 case *ofp.OfpOxmOfbField_Ipv4Dst:
810 valType, val32 = 4, val.Ipv4Dst
811 case *ofp.OfpOxmOfbField_TcpSrc:
812 valType, val32 = 4, val.TcpSrc
813 case *ofp.OfpOxmOfbField_TcpDst:
814 valType, val32 = 4, val.TcpDst
815 case *ofp.OfpOxmOfbField_UdpSrc:
816 valType, val32 = 4, val.UdpSrc
817 case *ofp.OfpOxmOfbField_UdpDst:
818 valType, val32 = 4, val.UdpDst
819 case *ofp.OfpOxmOfbField_SctpSrc:
820 valType, val32 = 4, val.SctpSrc
821 case *ofp.OfpOxmOfbField_SctpDst:
822 valType, val32 = 4, val.SctpDst
823 case *ofp.OfpOxmOfbField_Icmpv4Type:
824 valType, val32 = 4, val.Icmpv4Type
825 case *ofp.OfpOxmOfbField_Icmpv4Code:
826 valType, val32 = 4, val.Icmpv4Code
827 case *ofp.OfpOxmOfbField_ArpOp:
828 valType, val32 = 4, val.ArpOp
829 case *ofp.OfpOxmOfbField_ArpSpa:
830 valType, val32 = 4, val.ArpSpa
831 case *ofp.OfpOxmOfbField_ArpTpa:
832 valType, val32 = 4, val.ArpTpa
833 case *ofp.OfpOxmOfbField_ArpSha:
834 valType, valSlice = 1, val.ArpSha
835 case *ofp.OfpOxmOfbField_ArpTha:
836 valType, valSlice = 1, val.ArpTha
837 case *ofp.OfpOxmOfbField_Ipv6Src:
838 valType, valSlice = 1, val.Ipv6Src
839 case *ofp.OfpOxmOfbField_Ipv6Dst:
840 valType, valSlice = 1, val.Ipv6Dst
841 case *ofp.OfpOxmOfbField_Ipv6Flabel:
842 valType, val32 = 4, val.Ipv6Flabel
843 case *ofp.OfpOxmOfbField_Icmpv6Type:
844 valType, val32 = 4, val.Icmpv6Type
845 case *ofp.OfpOxmOfbField_Icmpv6Code:
846 valType, val32 = 4, val.Icmpv6Code
847 case *ofp.OfpOxmOfbField_Ipv6NdTarget:
848 valType, valSlice = 1, val.Ipv6NdTarget
849 case *ofp.OfpOxmOfbField_Ipv6NdSsl:
850 valType, valSlice = 1, val.Ipv6NdSsl
851 case *ofp.OfpOxmOfbField_Ipv6NdTll:
852 valType, valSlice = 1, val.Ipv6NdTll
853 case *ofp.OfpOxmOfbField_MplsLabel:
854 valType, val32 = 4, val.MplsLabel
855 case *ofp.OfpOxmOfbField_MplsTc:
856 valType, val32 = 4, val.MplsTc
857 case *ofp.OfpOxmOfbField_MplsBos:
858 valType, val32 = 4, val.MplsBos
859 case *ofp.OfpOxmOfbField_PbbIsid:
860 valType, val32 = 4, val.PbbIsid
861 case *ofp.OfpOxmOfbField_TunnelId:
862 valType, val64 = 8, val.TunnelId
863 case *ofp.OfpOxmOfbField_Ipv6Exthdr:
864 valType, val32 = 4, val.Ipv6Exthdr
865 default:
866 return fmt.Errorf("unknown OfpOxmField value type: %T", val)
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400867 }
Girish Gowdraf369c0a2020-05-15 13:27:38 -0700868 switch valType {
869 case 1: // slice
870 _, _ = md5Hash.Write(valSlice)
871 case 4: // uint32
872 binary.BigEndian.PutUint32(tmp[:4], val32)
873 _, _ = md5Hash.Write(tmp[:4])
874 case 8: // uint64
875 binary.BigEndian.PutUint64(tmp[:8], val64)
876 _, _ = md5Hash.Write(tmp[:8])
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000877 }
Girish Gowdraf369c0a2020-05-15 13:27:38 -0700878
879 // mask
880 if !field.HasMask {
881 tmp[0] = 0x00
882 _, _ = md5Hash.Write(tmp[:1]) // match hasMask = false
883 } else {
884 tmp[0] = 0x01
885 _, _ = md5Hash.Write(tmp[:1]) // match hasMask = true
886
887 maskType, mask32, mask64, maskSlice := uint8(0), uint32(0), uint64(0), []byte(nil)
888 switch mask := field.Mask.(type) {
889 case *ofp.OfpOxmOfbField_TableMetadataMask:
890 maskType, mask64 = 8, mask.TableMetadataMask
891 case *ofp.OfpOxmOfbField_EthDstMask:
892 maskType, maskSlice = 1, mask.EthDstMask
893 case *ofp.OfpOxmOfbField_EthSrcMask:
894 maskType, maskSlice = 1, mask.EthSrcMask
895 case *ofp.OfpOxmOfbField_VlanVidMask:
896 maskType, mask32 = 4, mask.VlanVidMask
897 case *ofp.OfpOxmOfbField_Ipv4SrcMask:
898 maskType, mask32 = 4, mask.Ipv4SrcMask
899 case *ofp.OfpOxmOfbField_Ipv4DstMask:
900 maskType, mask32 = 4, mask.Ipv4DstMask
901 case *ofp.OfpOxmOfbField_ArpSpaMask:
902 maskType, mask32 = 4, mask.ArpSpaMask
903 case *ofp.OfpOxmOfbField_ArpTpaMask:
904 maskType, mask32 = 4, mask.ArpTpaMask
905 case *ofp.OfpOxmOfbField_Ipv6SrcMask:
906 maskType, maskSlice = 1, mask.Ipv6SrcMask
907 case *ofp.OfpOxmOfbField_Ipv6DstMask:
908 maskType, maskSlice = 1, mask.Ipv6DstMask
909 case *ofp.OfpOxmOfbField_Ipv6FlabelMask:
910 maskType, mask32 = 4, mask.Ipv6FlabelMask
911 case *ofp.OfpOxmOfbField_PbbIsidMask:
912 maskType, mask32 = 4, mask.PbbIsidMask
913 case *ofp.OfpOxmOfbField_TunnelIdMask:
914 maskType, mask64 = 8, mask.TunnelIdMask
915 case *ofp.OfpOxmOfbField_Ipv6ExthdrMask:
916 maskType, mask32 = 4, mask.Ipv6ExthdrMask
917 case nil:
918 return fmt.Errorf("hasMask set to true, but no mask present")
919 default:
920 return fmt.Errorf("unknown OfpOxmField mask type: %T", mask)
921 }
922 switch maskType {
923 case 1: // slice
924 _, _ = md5Hash.Write(maskSlice)
925 case 4: // uint32
926 binary.BigEndian.PutUint32(tmp[:4], mask32)
927 _, _ = md5Hash.Write(tmp[:4])
928 case 8: // uint64
929 binary.BigEndian.PutUint64(tmp[:8], mask64)
930 _, _ = md5Hash.Write(tmp[:8])
931 }
932 }
933 return nil
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400934}
935
936// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
divyadesaid26f6b12020-03-19 06:30:28 +0000937func FlowStatsEntryFromFlowModMessage(mod *ofp.OfpFlowMod) (*ofp.OfpFlowStats, error) {
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400938 flow := &ofp.OfpFlowStats{}
939 if mod == nil {
divyadesaid26f6b12020-03-19 06:30:28 +0000940 return flow, nil
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400941 }
942 flow.TableId = mod.TableId
943 flow.Priority = mod.Priority
944 flow.IdleTimeout = mod.IdleTimeout
945 flow.HardTimeout = mod.HardTimeout
946 flow.Flags = mod.Flags
947 flow.Cookie = mod.Cookie
948 flow.Match = mod.Match
949 flow.Instructions = mod.Instructions
divyadesaid26f6b12020-03-19 06:30:28 +0000950 var err error
951 if flow.Id, err = HashFlowStats(flow); err != nil {
952 return nil, err
953 }
954
955 return flow, nil
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400956}
957
958func GroupEntryFromGroupMod(mod *ofp.OfpGroupMod) *ofp.OfpGroupEntry {
959 group := &ofp.OfpGroupEntry{}
960 if mod == nil {
961 return group
962 }
963 group.Desc = &ofp.OfpGroupDesc{Type: mod.Type, GroupId: mod.GroupId, Buckets: mod.Buckets}
964 group.Stats = &ofp.OfpGroupStats{GroupId: mod.GroupId}
965 //TODO do we need to instantiate bucket bins?
966 return group
967}
968
Manikkaraj kb1d51442019-07-23 10:41:02 -0400969// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
Neha Sharma96b7bf22020-06-15 10:37:32 +0000970func MeterEntryFromMeterMod(ctx context.Context, meterMod *ofp.OfpMeterMod) *ofp.OfpMeterEntry {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400971 bandStats := make([]*ofp.OfpMeterBandStats, 0)
972 meter := &ofp.OfpMeterEntry{Config: &ofp.OfpMeterConfig{},
973 Stats: &ofp.OfpMeterStats{BandStats: bandStats}}
974 if meterMod == nil {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000975 logger.Error(ctx, "Invalid meter mod command")
Manikkaraj kb1d51442019-07-23 10:41:02 -0400976 return meter
977 }
978 // config init
979 meter.Config.MeterId = meterMod.MeterId
980 meter.Config.Flags = meterMod.Flags
981 meter.Config.Bands = meterMod.Bands
982 // meter stats init
983 meter.Stats.MeterId = meterMod.MeterId
984 meter.Stats.FlowCount = 0
985 meter.Stats.PacketInCount = 0
986 meter.Stats.ByteInCount = 0
987 meter.Stats.DurationSec = 0
988 meter.Stats.DurationNsec = 0
989 // band stats init
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000990 for range meterMod.Bands {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400991 band := &ofp.OfpMeterBandStats{}
992 band.PacketBandCount = 0
993 band.ByteBandCount = 0
994 bandStats = append(bandStats, band)
995 }
996 meter.Stats.BandStats = bandStats
Neha Sharma96b7bf22020-06-15 10:37:32 +0000997 logger.Debugw(ctx, "Allocated meter entry", log.Fields{"meter": *meter})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400998 return meter
999
1000}
1001
1002func GetMeterIdFromFlow(flow *ofp.OfpFlowStats) uint32 {
1003 if flow != nil {
1004 for _, instruction := range flow.Instructions {
1005 if instruction.Type == uint32(METER_ACTION) {
1006 if meterInst := instruction.GetMeter(); meterInst != nil {
1007 return meterInst.GetMeterId()
1008 }
1009 }
1010 }
1011 }
1012
1013 return uint32(0)
1014}
1015
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001016func MkOxmFields(matchFields []ofp.OfpOxmField) []*ofp.OfpOxmField {
1017 oxmFields := make([]*ofp.OfpOxmField, 0)
1018 for _, matchField := range matchFields {
1019 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
1020 oxmFields = append(oxmFields, &oxmField)
1021 }
1022 return oxmFields
1023}
1024
1025func MkInstructionsFromActions(actions []*ofp.OfpAction) []*ofp.OfpInstruction {
1026 instructions := make([]*ofp.OfpInstruction, 0)
1027 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
1028 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
1029 instructions = append(instructions, &instruction)
1030 return instructions
1031}
1032
1033// Convenience function to generare ofp_flow_mod message with OXM BASIC match composed from the match_fields, and
1034// single APPLY_ACTIONS instruction with a list if ofp_action objects.
1035func MkSimpleFlowMod(matchFields []*ofp.OfpOxmField, actions []*ofp.OfpAction, command *ofp.OfpFlowModCommand, kw OfpFlowModArgs) *ofp.OfpFlowMod {
1036
1037 // Process actions instructions
1038 instructions := make([]*ofp.OfpInstruction, 0)
1039 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
1040 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
1041 instructions = append(instructions, &instruction)
1042
1043 // Process next table
1044 if tableId := GetNextTableId(kw); tableId != nil {
1045 var instGotoTable ofp.OfpInstruction_GotoTable
1046 instGotoTable.GotoTable = &ofp.OfpInstructionGotoTable{TableId: *tableId}
1047 inst := ofp.OfpInstruction{Type: uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE), Data: &instGotoTable}
1048 instructions = append(instructions, &inst)
1049 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001050 // Process meter action
1051 if meterId := GetMeterIdFlowModArgs(kw); meterId != 0 {
1052 var instMeter ofp.OfpInstruction_Meter
1053 instMeter.Meter = &ofp.OfpInstructionMeter{MeterId: meterId}
1054 inst := ofp.OfpInstruction{Type: uint32(METER_ACTION), Data: &instMeter}
1055 instructions = append(instructions, &inst)
1056 }
1057 //process write_metadata action
1058 if metadata := GetMetadataFlowModArgs(kw); metadata != 0 {
1059 var instWriteMetadata ofp.OfpInstruction_WriteMetadata
1060 instWriteMetadata.WriteMetadata = &ofp.OfpInstructionWriteMetadata{Metadata: metadata}
1061 inst := ofp.OfpInstruction{Type: uint32(WRITE_METADATA), Data: &instWriteMetadata}
1062 instructions = append(instructions, &inst)
1063 }
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001064
1065 // Process match fields
1066 oxmFields := make([]*ofp.OfpOxmField, 0)
1067 for _, matchField := range matchFields {
1068 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
1069 oxmFields = append(oxmFields, &oxmField)
1070 }
1071 var match ofp.OfpMatch
1072 match.Type = ofp.OfpMatchType_OFPMT_OXM
1073 match.OxmFields = oxmFields
1074
1075 // Create ofp_flow_message
1076 msg := &ofp.OfpFlowMod{}
1077 if command == nil {
1078 msg.Command = ofp.OfpFlowModCommand_OFPFC_ADD
1079 } else {
1080 msg.Command = *command
1081 }
1082 msg.Instructions = instructions
1083 msg.Match = &match
1084
1085 // Set the variadic argument values
1086 msg = setVariadicModAttributes(msg, kw)
1087
1088 return msg
1089}
1090
1091func MkMulticastGroupMod(groupId uint32, buckets []*ofp.OfpBucket, command *ofp.OfpGroupModCommand) *ofp.OfpGroupMod {
1092 group := &ofp.OfpGroupMod{}
1093 if command == nil {
1094 group.Command = ofp.OfpGroupModCommand_OFPGC_ADD
1095 } else {
1096 group.Command = *command
1097 }
1098 group.Type = ofp.OfpGroupType_OFPGT_ALL
1099 group.GroupId = groupId
1100 group.Buckets = buckets
1101 return group
1102}
1103
1104//SetVariadicModAttributes sets only uint64 or uint32 fields of the ofp_flow_mod message
1105func setVariadicModAttributes(mod *ofp.OfpFlowMod, args OfpFlowModArgs) *ofp.OfpFlowMod {
1106 if args == nil {
1107 return mod
1108 }
1109 for key, val := range args {
1110 switch key {
1111 case "cookie":
1112 mod.Cookie = val
1113 case "cookie_mask":
1114 mod.CookieMask = val
1115 case "table_id":
1116 mod.TableId = uint32(val)
1117 case "idle_timeout":
1118 mod.IdleTimeout = uint32(val)
1119 case "hard_timeout":
1120 mod.HardTimeout = uint32(val)
1121 case "priority":
1122 mod.Priority = uint32(val)
1123 case "buffer_id":
1124 mod.BufferId = uint32(val)
1125 case "out_port":
1126 mod.OutPort = uint32(val)
1127 case "out_group":
1128 mod.OutGroup = uint32(val)
1129 case "flags":
1130 mod.Flags = uint32(val)
1131 }
1132 }
1133 return mod
1134}
1135
1136func MkPacketIn(port uint32, packet []byte) *ofp.OfpPacketIn {
1137 packetIn := &ofp.OfpPacketIn{
1138 Reason: ofp.OfpPacketInReason_OFPR_ACTION,
1139 Match: &ofp.OfpMatch{
1140 Type: ofp.OfpMatchType_OFPMT_OXM,
1141 OxmFields: []*ofp.OfpOxmField{
1142 {
1143 OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
1144 Field: &ofp.OfpOxmField_OfbField{
1145 OfbField: InPort(port)},
1146 },
1147 },
1148 },
1149 Data: packet,
1150 }
1151 return packetIn
1152}
1153
1154// MkFlowStat is a helper method to build flows
divyadesaid26f6b12020-03-19 06:30:28 +00001155func MkFlowStat(fa *FlowArgs) (*ofp.OfpFlowStats, error) {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001156 //Build the match-fields
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001157 matchFields := make([]*ofp.OfpOxmField, 0)
1158 for _, val := range fa.MatchFields {
1159 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
1160 }
1161 return FlowStatsEntryFromFlowModMessage(MkSimpleFlowMod(matchFields, fa.Actions, fa.Command, fa.KV))
1162}
1163
1164func MkGroupStat(ga *GroupArgs) *ofp.OfpGroupEntry {
1165 return GroupEntryFromGroupMod(MkMulticastGroupMod(ga.GroupId, ga.Buckets, ga.Command))
1166}
1167
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001168type OfpFlowModArgs map[string]uint64
1169
1170type FlowArgs struct {
1171 MatchFields []*ofp.OfpOxmOfbField
1172 Actions []*ofp.OfpAction
1173 Command *ofp.OfpFlowModCommand
1174 Priority uint32
1175 KV OfpFlowModArgs
1176}
1177
1178type GroupArgs struct {
1179 GroupId uint32
1180 Buckets []*ofp.OfpBucket
1181 Command *ofp.OfpGroupModCommand
1182}
1183
1184type FlowsAndGroups struct {
1185 Flows *ordered_map.OrderedMap
1186 Groups *ordered_map.OrderedMap
1187}
1188
1189func NewFlowsAndGroups() *FlowsAndGroups {
1190 var fg FlowsAndGroups
1191 fg.Flows = ordered_map.NewOrderedMap()
1192 fg.Groups = ordered_map.NewOrderedMap()
1193 return &fg
1194}
1195
1196func (fg *FlowsAndGroups) Copy() *FlowsAndGroups {
1197 copyFG := NewFlowsAndGroups()
1198 iter := fg.Flows.IterFunc()
1199 for kv, ok := iter(); ok; kv, ok = iter() {
1200 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1201 copyFG.Flows.Set(kv.Key, proto.Clone(protoMsg))
1202 }
1203 }
1204 iter = fg.Groups.IterFunc()
1205 for kv, ok := iter(); ok; kv, ok = iter() {
1206 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1207 copyFG.Groups.Set(kv.Key, proto.Clone(protoMsg))
1208 }
1209 }
1210 return copyFG
1211}
1212
1213func (fg *FlowsAndGroups) GetFlow(index int) *ofp.OfpFlowStats {
1214 iter := fg.Flows.IterFunc()
1215 pos := 0
1216 for kv, ok := iter(); ok; kv, ok = iter() {
1217 if pos == index {
1218 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1219 return protoMsg
1220 }
1221 return nil
1222 }
1223 pos += 1
1224 }
1225 return nil
1226}
1227
1228func (fg *FlowsAndGroups) ListFlows() []*ofp.OfpFlowStats {
1229 flows := make([]*ofp.OfpFlowStats, 0)
1230 iter := fg.Flows.IterFunc()
1231 for kv, ok := iter(); ok; kv, ok = iter() {
1232 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1233 flows = append(flows, protoMsg)
1234 }
1235 }
1236 return flows
1237}
1238
1239func (fg *FlowsAndGroups) ListGroups() []*ofp.OfpGroupEntry {
1240 groups := make([]*ofp.OfpGroupEntry, 0)
1241 iter := fg.Groups.IterFunc()
1242 for kv, ok := iter(); ok; kv, ok = iter() {
1243 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1244 groups = append(groups, protoMsg)
1245 }
1246 }
1247 return groups
1248}
1249
1250func (fg *FlowsAndGroups) String() string {
1251 var buffer bytes.Buffer
1252 iter := fg.Flows.IterFunc()
1253 for kv, ok := iter(); ok; kv, ok = iter() {
1254 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1255 buffer.WriteString("\nFlow:\n")
1256 buffer.WriteString(proto.MarshalTextString(protoMsg))
1257 buffer.WriteString("\n")
1258 }
1259 }
1260 iter = fg.Groups.IterFunc()
1261 for kv, ok := iter(); ok; kv, ok = iter() {
1262 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1263 buffer.WriteString("\nGroup:\n")
1264 buffer.WriteString(proto.MarshalTextString(protoMsg))
1265 buffer.WriteString("\n")
1266 }
1267 }
1268 return buffer.String()
1269}
1270
1271func (fg *FlowsAndGroups) AddFlow(flow *ofp.OfpFlowStats) {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001272 if flow == nil {
1273 return
1274 }
1275
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001276 if fg.Flows == nil {
1277 fg.Flows = ordered_map.NewOrderedMap()
1278 }
1279 if fg.Groups == nil {
1280 fg.Groups = ordered_map.NewOrderedMap()
1281 }
1282 //Add flow only if absent
1283 if _, exist := fg.Flows.Get(flow.Id); !exist {
1284 fg.Flows.Set(flow.Id, flow)
1285 }
1286}
1287
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001288func (fg *FlowsAndGroups) AddGroup(group *ofp.OfpGroupEntry) {
1289 if group == nil {
1290 return
1291 }
1292
1293 if fg.Flows == nil {
1294 fg.Flows = ordered_map.NewOrderedMap()
1295 }
1296 if fg.Groups == nil {
1297 fg.Groups = ordered_map.NewOrderedMap()
1298 }
1299 //Add group only if absent
1300 if _, exist := fg.Groups.Get(group.Desc.GroupId); !exist {
1301 fg.Groups.Set(group.Desc.GroupId, group)
1302 }
1303}
1304
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001305//AddFrom add flows and groups from the argument into this structure only if they do not already exist
1306func (fg *FlowsAndGroups) AddFrom(from *FlowsAndGroups) {
1307 iter := from.Flows.IterFunc()
1308 for kv, ok := iter(); ok; kv, ok = iter() {
1309 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1310 if _, exist := fg.Flows.Get(protoMsg.Id); !exist {
1311 fg.Flows.Set(protoMsg.Id, protoMsg)
1312 }
1313 }
1314 }
1315 iter = from.Groups.IterFunc()
1316 for kv, ok := iter(); ok; kv, ok = iter() {
1317 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1318 if _, exist := fg.Groups.Get(protoMsg.Stats.GroupId); !exist {
1319 fg.Groups.Set(protoMsg.Stats.GroupId, protoMsg)
1320 }
1321 }
1322 }
1323}
1324
1325type DeviceRules struct {
1326 Rules map[string]*FlowsAndGroups
1327}
1328
1329func NewDeviceRules() *DeviceRules {
1330 var dr DeviceRules
1331 dr.Rules = make(map[string]*FlowsAndGroups)
1332 return &dr
1333}
1334
1335func (dr *DeviceRules) Copy() *DeviceRules {
1336 copyDR := NewDeviceRules()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001337 if dr != nil {
1338 for key, val := range dr.Rules {
1339 if val != nil {
1340 copyDR.Rules[key] = val.Copy()
1341 }
Matt Jeanneret384d8c92019-05-06 14:27:31 -04001342 }
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001343 }
1344 return copyDR
1345}
1346
1347func (dr *DeviceRules) ClearFlows(deviceId string) {
1348 if _, exist := dr.Rules[deviceId]; exist {
1349 dr.Rules[deviceId].Flows = ordered_map.NewOrderedMap()
1350 }
1351}
1352
Matt Jeanneret384d8c92019-05-06 14:27:31 -04001353func (dr *DeviceRules) FilterRules(deviceIds map[string]string) *DeviceRules {
1354 filteredDR := NewDeviceRules()
1355 for key, val := range dr.Rules {
1356 if _, exist := deviceIds[key]; exist {
1357 filteredDR.Rules[key] = val.Copy()
1358 }
1359 }
1360 return filteredDR
1361}
1362
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001363func (dr *DeviceRules) AddFlow(deviceId string, flow *ofp.OfpFlowStats) {
1364 if _, exist := dr.Rules[deviceId]; !exist {
1365 dr.Rules[deviceId] = NewFlowsAndGroups()
1366 }
1367 dr.Rules[deviceId].AddFlow(flow)
1368}
1369
1370func (dr *DeviceRules) GetRules() map[string]*FlowsAndGroups {
1371 return dr.Rules
1372}
1373
1374func (dr *DeviceRules) String() string {
1375 var buffer bytes.Buffer
1376 for key, value := range dr.Rules {
1377 buffer.WriteString("DeviceId:")
1378 buffer.WriteString(key)
1379 buffer.WriteString(value.String())
1380 buffer.WriteString("\n\n")
1381 }
1382 return buffer.String()
1383}
1384
1385func (dr *DeviceRules) AddFlowsAndGroup(deviceId string, fg *FlowsAndGroups) {
1386 if _, ok := dr.Rules[deviceId]; !ok {
1387 dr.Rules[deviceId] = NewFlowsAndGroups()
1388 }
1389 dr.Rules[deviceId] = fg
1390}
1391
1392// CreateEntryIfNotExist creates a new deviceId in the Map if it does not exist and assigns an
1393// empty FlowsAndGroups to it. Otherwise, it does nothing.
1394func (dr *DeviceRules) CreateEntryIfNotExist(deviceId string) {
1395 if _, ok := dr.Rules[deviceId]; !ok {
1396 dr.Rules[deviceId] = NewFlowsAndGroups()
1397 }
1398}
1399
1400/*
1401 * Common flow routines
1402 */
1403
1404//FindOverlappingFlows return a list of overlapping flow(s) where mod is the flow request
1405func FindOverlappingFlows(flows []*ofp.OfpFlowStats, mod *ofp.OfpFlowMod) []*ofp.OfpFlowStats {
1406 return nil //TODO - complete implementation
1407}
1408
1409// FindFlowById returns the index of the flow in the flows array if present. Otherwise, it returns -1
1410func FindFlowById(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
1411 for idx, f := range flows {
1412 if flow.Id == f.Id {
1413 return idx
1414 }
1415 }
1416 return -1
1417}
1418
1419// FindFlows returns the index in flows where flow if present. Otherwise, it returns -1
1420func FindFlows(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
1421 for idx, f := range flows {
Girish Gowdraf369c0a2020-05-15 13:27:38 -07001422 if f.Id == flow.Id {
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001423 return idx
1424 }
1425 }
1426 return -1
1427}
1428
1429//FlowMatch returns true if two flows matches on the following flow attributes:
1430//TableId, Priority, Flags, Cookie, Match
1431func FlowMatch(f1 *ofp.OfpFlowStats, f2 *ofp.OfpFlowStats) bool {
Girish Gowdraf369c0a2020-05-15 13:27:38 -07001432 return f1 != nil && f2 != nil && f1.Id == f2.Id
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001433}
1434
1435//FlowMatchesMod returns True if given flow is "covered" by the wildcard flow_mod, taking into consideration of
1436//both exact matches as well as masks-based match fields if any. Otherwise return False
1437func FlowMatchesMod(flow *ofp.OfpFlowStats, mod *ofp.OfpFlowMod) bool {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001438 if flow == nil || mod == nil {
1439 return false
1440 }
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001441 //Check if flow.cookie is covered by mod.cookie and mod.cookie_mask
1442 if (flow.Cookie & mod.CookieMask) != (mod.Cookie & mod.CookieMask) {
1443 return false
1444 }
1445
1446 //Check if flow.table_id is covered by flow_mod.table_id
1447 if mod.TableId != uint32(ofp.OfpTable_OFPTT_ALL) && flow.TableId != mod.TableId {
1448 return false
1449 }
1450
1451 //Check out_port
1452 if (mod.OutPort&0x7fffffff) != uint32(ofp.OfpPortNo_OFPP_ANY) && !FlowHasOutPort(flow, mod.OutPort) {
1453 return false
1454 }
1455
1456 // Check out_group
1457 if (mod.OutGroup&0x7fffffff) != uint32(ofp.OfpGroup_OFPG_ANY) && !FlowHasOutGroup(flow, mod.OutGroup) {
1458 return false
1459 }
1460
1461 //Priority is ignored
1462
1463 //Check match condition
1464 //If the flow_mod match field is empty, that is a special case and indicates the flow entry matches
Mahir Gunyele77977b2019-06-27 05:36:22 -07001465 if (mod.Match == nil) || (mod.Match.OxmFields == nil) || (len(mod.Match.OxmFields) == 0) {
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001466 //If we got this far and the match is empty in the flow spec, than the flow matches
1467 return true
1468 } // TODO : implement the flow match analysis
1469 return false
1470
1471}
1472
1473//FlowHasOutPort returns True if flow has a output command with the given out_port
1474func FlowHasOutPort(flow *ofp.OfpFlowStats, outPort uint32) bool {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001475 if flow == nil {
1476 return false
1477 }
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001478 for _, instruction := range flow.Instructions {
1479 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
1480 if instruction.GetActions() == nil {
1481 return false
1482 }
1483 for _, action := range instruction.GetActions().Actions {
1484 if action.Type == ofp.OfpActionType_OFPAT_OUTPUT {
1485 if (action.GetOutput() != nil) && (action.GetOutput().Port == outPort) {
1486 return true
1487 }
1488 }
1489
1490 }
1491 }
1492 }
1493 return false
1494}
1495
1496//FlowHasOutGroup return True if flow has a output command with the given out_group
1497func FlowHasOutGroup(flow *ofp.OfpFlowStats, groupID uint32) bool {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001498 if flow == nil {
1499 return false
1500 }
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001501 for _, instruction := range flow.Instructions {
1502 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
1503 if instruction.GetActions() == nil {
1504 return false
1505 }
1506 for _, action := range instruction.GetActions().Actions {
1507 if action.Type == ofp.OfpActionType_OFPAT_GROUP {
1508 if (action.GetGroup() != nil) && (action.GetGroup().GroupId == groupID) {
1509 return true
1510 }
1511 }
1512
1513 }
1514 }
1515 }
1516 return false
1517}
1518
1519//FindGroup returns index of group if found, else returns -1
1520func FindGroup(groups []*ofp.OfpGroupEntry, groupId uint32) int {
1521 for idx, group := range groups {
1522 if group.Desc.GroupId == groupId {
1523 return idx
1524 }
1525 }
1526 return -1
1527}
1528
1529func FlowsDeleteByGroupId(flows []*ofp.OfpFlowStats, groupId uint32) (bool, []*ofp.OfpFlowStats) {
1530 toKeep := make([]*ofp.OfpFlowStats, 0)
1531
1532 for _, f := range flows {
1533 if !FlowHasOutGroup(f, groupId) {
1534 toKeep = append(toKeep, f)
1535 }
1536 }
1537 return len(toKeep) < len(flows), toKeep
1538}
Mahir Gunyele77977b2019-06-27 05:36:22 -07001539
1540func ToOfpOxmField(from []*ofp.OfpOxmOfbField) []*ofp.OfpOxmField {
1541 matchFields := make([]*ofp.OfpOxmField, 0)
1542 for _, val := range from {
1543 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
1544 }
1545 return matchFields
1546}
Girish Gowdra54934262019-11-13 14:19:55 +05301547
1548//IsMulticastIp returns true if the ip starts with the byte sequence of 1110;
1549//false otherwise.
1550func IsMulticastIp(ip uint32) bool {
1551 return ip>>28 == 14
1552}
1553
1554//ConvertToMulticastMacInt returns equivalent mac address of the given multicast ip address
1555func ConvertToMulticastMacInt(ip uint32) uint64 {
1556 //get last 23 bits of ip address by ip & 00000000011111111111111111111111
1557 theLast23BitsOfIp := ip & 8388607
1558 // perform OR with 0x1005E000000 to build mcast mac address
1559 return 1101088686080 | uint64(theLast23BitsOfIp)
1560}
1561
1562//ConvertToMulticastMacBytes returns equivalent mac address of the given multicast ip address
1563func ConvertToMulticastMacBytes(ip uint32) []byte {
1564 mac := ConvertToMulticastMacInt(ip)
1565 var b bytes.Buffer
1566 // catalyze (48 bits) in binary:111111110000000000000000000000000000000000000000
1567 catalyze := uint64(280375465082880)
1568 //convert each octet to decimal
1569 for i := 0; i < 6; i++ {
1570 if i != 0 {
1571 catalyze = catalyze >> 8
1572 }
1573 octet := mac & catalyze
1574 octetDecimal := octet >> uint8(40-i*8)
1575 b.WriteByte(byte(octetDecimal))
1576 }
1577 return b.Bytes()
1578}
Girish Gowdra8a0bdcd2021-05-13 12:31:04 -07001579
1580func GetMeterIdFromWriteMetadata(ctx context.Context, flow *ofp.OfpFlowStats) uint32 {
1581 /*
1582 Write metadata instruction value (metadata) is 8 bytes:
1583 MS 2 bytes: C Tag
1584 Next 2 bytes: Technology Profile Id
1585 Next 4 bytes: Port number (uni or nni) or MeterId
1586 This is set in the ONOS OltPipeline as a write metadata instruction
1587 */
1588 var meterID uint32 = 0
1589 md := GetMetadataFromWriteMetadataAction(ctx, flow)
1590 logger.Debugw(ctx, "found-metadata-for-egress/uni-port", log.Fields{"metadata": md})
1591 if md != 0 {
1592 meterID = uint32(md & 0xFFFFFFFF)
1593 logger.Debugw(ctx, "found-meterID-in-write-metadata-action", log.Fields{"meterID": meterID})
1594 }
1595 return meterID
1596}
1597
1598func SetMeterIdToFlow(flow *ofp.OfpFlowStats, meterId uint32) {
1599 if flow != nil {
1600 for _, instruction := range flow.Instructions {
1601 if instruction.Type == uint32(METER_ACTION) {
1602 if meterInst := instruction.GetMeter(); meterInst != nil {
1603 meterInst.MeterId = meterId
1604 }
1605 }
1606 }
1607 }
1608}