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