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