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