blob: 4de929ff46f5fa45cfd78e80f224214ff16fc346 [file] [log] [blame]
khenaidoo89b0e942018-10-21 21:11:33 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Scott Bakerb671a862019-10-24 10:53:40 -070016package flows
khenaidoo89b0e942018-10-21 21:11:33 -040017
18import (
19 "bytes"
khenaidoo68c930b2019-05-13 11:46:51 -040020 "crypto/md5"
21 "fmt"
khenaidoo89b0e942018-10-21 21:11:33 -040022 "github.com/cevaris/ordered_map"
23 "github.com/gogo/protobuf/proto"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080024 "github.com/opencord/voltha-lib-go/v3/pkg/log"
25 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
khenaidoo68c930b2019-05-13 11:46:51 -040026 "math/big"
khenaidoo19d7b632018-10-30 10:49:50 -040027 "strings"
khenaidoo89b0e942018-10-21 21:11:33 -040028)
29
khenaidoo68c930b2019-05-13 11:46:51 -040030var (
31 // Instructions shortcut
Manikkaraj kb1a10922019-07-29 12:10:34 -040032 APPLY_ACTIONS = ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS
33 WRITE_METADATA = ofp.OfpInstructionType_OFPIT_WRITE_METADATA
34 METER_ACTION = ofp.OfpInstructionType_OFPIT_METER
khenaidoo68c930b2019-05-13 11:46:51 -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 kb1a10922019-07-29 12:10:34 -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 Jeanneretb423bad2019-10-10 20:42:19 -0400477func GetVlanVid(flow *ofp.OfpFlowStats) *uint32 {
478 if flow == nil {
479 return nil
480 }
481 for _, field := range GetOfbFields(flow) {
482 if field.Type == VLAN_VID {
483 ret := field.GetVlanVid()
484 return &ret
485 }
486 }
487 // Dont return 0 if the field is missing as vlan id value 0 has meaning and cannot be overloaded as "not found"
488 return nil
489}
490
khenaidoo68c930b2019-05-13 11:46:51 -0400491func GetTunnelId(flow *ofp.OfpFlowStats) uint64 {
492 if flow == nil {
493 return 0
494 }
495 for _, field := range GetOfbFields(flow) {
496 if field.Type == TUNNEL_ID {
497 return field.GetTunnelId()
498 }
499 }
500 return 0
501}
502
503//GetMetaData - legacy get method (only want lower 32 bits)
504func GetMetaData(flow *ofp.OfpFlowStats) uint32 {
505 if flow == nil {
506 return 0
507 }
508 for _, field := range GetOfbFields(flow) {
509 if field.Type == METADATA {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400510 return uint32(field.GetTableMetadata() & 0xFFFFFFFF)
khenaidoo68c930b2019-05-13 11:46:51 -0400511 }
512 }
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800513 logger.Debug("No-metadata-present")
khenaidoo68c930b2019-05-13 11:46:51 -0400514 return 0
515}
516
517func GetMetaData64Bit(flow *ofp.OfpFlowStats) uint64 {
518 if flow == nil {
519 return 0
520 }
521 for _, field := range GetOfbFields(flow) {
522 if field.Type == METADATA {
523 return field.GetTableMetadata()
524 }
525 }
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800526 logger.Debug("No-metadata-present")
khenaidoo68c930b2019-05-13 11:46:51 -0400527 return 0
528}
529
Manikkaraj kb1a10922019-07-29 12:10:34 -0400530// function returns write metadata value from write_metadata action field
531func GetMetadataFromWriteMetadataAction(flow *ofp.OfpFlowStats) uint64 {
532 if flow != nil {
533 for _, instruction := range flow.Instructions {
534 if instruction.Type == uint32(WRITE_METADATA) {
535 if writeMetadata := instruction.GetWriteMetadata(); writeMetadata != nil {
536 return writeMetadata.GetMetadata()
537 }
538 }
539 }
khenaidoo68c930b2019-05-13 11:46:51 -0400540 }
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800541 logger.Debugw("No-write-metadata-present", log.Fields{"flow": flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400542 return 0
543}
544
545func GetTechProfileIDFromWriteMetaData(metadata uint64) uint16 {
546 /*
547 Write metadata instruction value (metadata) is 8 bytes:
548 MS 2 bytes: C Tag
549 Next 2 bytes: Technology Profile Id
550 Next 4 bytes: Port number (uni or nni)
551
552 This is set in the ONOS OltPipeline as a write metadata instruction
553 */
554 var tpId uint16 = 0
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800555 logger.Debugw("Write metadata value for Techprofile ID", log.Fields{"metadata": metadata})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400556 if metadata != 0 {
557 tpId = uint16((metadata >> 32) & 0xFFFF)
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800558 logger.Debugw("Found techprofile ID from write metadata action", log.Fields{"tpid": tpId})
khenaidoo68c930b2019-05-13 11:46:51 -0400559 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400560 return tpId
561}
562
563func GetEgressPortNumberFromWriteMetadata(flow *ofp.OfpFlowStats) uint32 {
564 /*
565 Write metadata instruction value (metadata) is 8 bytes:
566 MS 2 bytes: C Tag
567 Next 2 bytes: Technology Profile Id
568 Next 4 bytes: Port number (uni or nni)
569 This is set in the ONOS OltPipeline as a write metadata instruction
570 */
571 var uniPort uint32 = 0
572 md := GetMetadataFromWriteMetadataAction(flow)
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800573 logger.Debugw("Metadata found for egress/uni port ", log.Fields{"metadata": md})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400574 if md != 0 {
575 uniPort = uint32(md & 0xFFFFFFFF)
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800576 logger.Debugw("Found EgressPort from write metadata action", log.Fields{"egress_port": uniPort})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400577 }
578 return uniPort
579
580}
581
582func GetInnerTagFromMetaData(flow *ofp.OfpFlowStats) uint16 {
583 /*
584 Write metadata instruction value (metadata) is 8 bytes:
585 MS 2 bytes: C Tag
586 Next 2 bytes: Technology Profile Id
587 Next 4 bytes: Port number (uni or nni)
588 This is set in the ONOS OltPipeline as a write metadata instruction
589 */
590 var innerTag uint16 = 0
591 md := GetMetadataFromWriteMetadataAction(flow)
592 if md != 0 {
593 innerTag = uint16((md >> 48) & 0xFFFF)
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800594 logger.Debugw("Found CVLAN from write metadate action", log.Fields{"c_vlan": innerTag})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400595 }
596 return innerTag
khenaidoo68c930b2019-05-13 11:46:51 -0400597}
598
599//GetInnerTagFromMetaData retrieves the inner tag from the Metadata_ofp. The port number (UNI on ONU) is in the
600// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
601//// a Metadata_ofp field
Manikkaraj kb1a10922019-07-29 12:10:34 -0400602/*func GetInnerTagFromMetaData(flow *ofp.OfpFlowStats) uint64 {
khenaidoo68c930b2019-05-13 11:46:51 -0400603 md := GetMetaData64Bit(flow)
604 if md == 0 {
605 return 0
606 }
607 if md <= 0xffffffff {
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800608 logger.Debugw("onos-upgrade-suggested", logger.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
khenaidoo68c930b2019-05-13 11:46:51 -0400609 return md
610 }
611 return (md >> 32) & 0xffffffff
Manikkaraj kb1a10922019-07-29 12:10:34 -0400612}*/
khenaidoo68c930b2019-05-13 11:46:51 -0400613
614// Extract the child device port from a flow that contains the parent device peer port. Typically the UNI port of an
615// ONU child device. Per TST agreement this will be the lower 32 bits of tunnel id reserving upper 32 bits for later
616// use
617func GetChildPortFromTunnelId(flow *ofp.OfpFlowStats) uint32 {
618 tid := GetTunnelId(flow)
619 if tid == 0 {
620 return 0
621 }
622 // Per TST agreement we are keeping any child port id (uni port id) in the lower 32 bits
623 return uint32(tid & 0xffffffff)
624}
625
626func HasNextTable(flow *ofp.OfpFlowStats) bool {
627 if flow == nil {
628 return false
629 }
630 return GetGotoTableId(flow) != 0
631}
632
633func GetGroup(flow *ofp.OfpFlowStats) uint32 {
634 if flow == nil {
635 return 0
636 }
637 for _, action := range GetActions(flow) {
638 if action.Type == GROUP {
639 grp := action.GetGroup()
640 if grp == nil {
641 return 0
642 }
643 return grp.GetGroupId()
644 }
645 }
646 return 0
647}
648
649func HasGroup(flow *ofp.OfpFlowStats) bool {
650 return GetGroup(flow) != 0
651}
652
653// GetNextTableId returns the next table ID if the "table_id" is present in the map, otherwise return nil
654func GetNextTableId(kw OfpFlowModArgs) *uint32 {
655 if val, exist := kw["table_id"]; exist {
656 ret := uint32(val)
657 return &ret
658 }
659 return nil
660}
661
Manikkaraj kb1a10922019-07-29 12:10:34 -0400662// GetMeterIdFlowModArgs returns the meterId if the "meter_id" is present in the map, otherwise return 0
663func GetMeterIdFlowModArgs(kw OfpFlowModArgs) uint32 {
664 if val, exist := kw["meter_id"]; exist {
665 return uint32(val)
666 }
667 return 0
668}
669
670// Function returns the metadata if the "write_metadata" is present in the map, otherwise return nil
671func GetMetadataFlowModArgs(kw OfpFlowModArgs) uint64 {
672 if val, exist := kw["write_metadata"]; exist {
673 ret := uint64(val)
674 return ret
675 }
676 return 0
677}
678
khenaidoo68c930b2019-05-13 11:46:51 -0400679// Return unique 64-bit integer hash for flow covering the following attributes:
680// 'table_id', 'priority', 'flags', 'cookie', 'match', '_instruction_string'
681func HashFlowStats(flow *ofp.OfpFlowStats) uint64 {
682 if flow == nil { // Should never happen
683 return 0
684 }
685 // Create string with the instructions field first
686 var instructionString bytes.Buffer
687 for _, instruction := range flow.Instructions {
688 instructionString.WriteString(instruction.String())
689 }
690 var flowString = fmt.Sprintf("%d%d%d%d%s%s", flow.TableId, flow.Priority, flow.Flags, flow.Cookie, flow.Match.String(), instructionString.String())
691 h := md5.New()
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000692 if _, err := h.Write([]byte(flowString)); err != nil {
693 logger.Errorw("hash-flow-status", log.Fields{"error": err})
694 return 0
695 }
khenaidoo68c930b2019-05-13 11:46:51 -0400696 hash := big.NewInt(0)
697 hash.SetBytes(h.Sum(nil))
698 return hash.Uint64()
699}
700
701// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
702func FlowStatsEntryFromFlowModMessage(mod *ofp.OfpFlowMod) *ofp.OfpFlowStats {
703 flow := &ofp.OfpFlowStats{}
704 if mod == nil {
705 return flow
706 }
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
715 flow.Id = HashFlowStats(flow)
716 return flow
717}
718
719func GroupEntryFromGroupMod(mod *ofp.OfpGroupMod) *ofp.OfpGroupEntry {
720 group := &ofp.OfpGroupEntry{}
721 if mod == nil {
722 return group
723 }
724 group.Desc = &ofp.OfpGroupDesc{Type: mod.Type, GroupId: mod.GroupId, Buckets: mod.Buckets}
725 group.Stats = &ofp.OfpGroupStats{GroupId: mod.GroupId}
726 //TODO do we need to instantiate bucket bins?
727 return group
728}
729
Manikkaraj kb1a10922019-07-29 12:10:34 -0400730// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
731func MeterEntryFromMeterMod(meterMod *ofp.OfpMeterMod) *ofp.OfpMeterEntry {
732 bandStats := make([]*ofp.OfpMeterBandStats, 0)
733 meter := &ofp.OfpMeterEntry{Config: &ofp.OfpMeterConfig{},
734 Stats: &ofp.OfpMeterStats{BandStats: bandStats}}
735 if meterMod == nil {
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800736 logger.Error("Invalid meter mod command")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400737 return meter
738 }
739 // config init
740 meter.Config.MeterId = meterMod.MeterId
741 meter.Config.Flags = meterMod.Flags
742 meter.Config.Bands = meterMod.Bands
743 // meter stats init
744 meter.Stats.MeterId = meterMod.MeterId
745 meter.Stats.FlowCount = 0
746 meter.Stats.PacketInCount = 0
747 meter.Stats.ByteInCount = 0
748 meter.Stats.DurationSec = 0
749 meter.Stats.DurationNsec = 0
750 // band stats init
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000751 for range meterMod.Bands {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400752 band := &ofp.OfpMeterBandStats{}
753 band.PacketBandCount = 0
754 band.ByteBandCount = 0
755 bandStats = append(bandStats, band)
756 }
757 meter.Stats.BandStats = bandStats
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800758 logger.Debugw("Allocated meter entry", log.Fields{"meter": *meter})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400759 return meter
760
761}
762
763func GetMeterIdFromFlow(flow *ofp.OfpFlowStats) uint32 {
764 if flow != nil {
765 for _, instruction := range flow.Instructions {
766 if instruction.Type == uint32(METER_ACTION) {
767 if meterInst := instruction.GetMeter(); meterInst != nil {
768 return meterInst.GetMeterId()
769 }
770 }
771 }
772 }
773
774 return uint32(0)
775}
776
khenaidoo68c930b2019-05-13 11:46:51 -0400777func MkOxmFields(matchFields []ofp.OfpOxmField) []*ofp.OfpOxmField {
778 oxmFields := make([]*ofp.OfpOxmField, 0)
779 for _, matchField := range matchFields {
780 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
781 oxmFields = append(oxmFields, &oxmField)
782 }
783 return oxmFields
784}
785
786func MkInstructionsFromActions(actions []*ofp.OfpAction) []*ofp.OfpInstruction {
787 instructions := make([]*ofp.OfpInstruction, 0)
788 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
789 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
790 instructions = append(instructions, &instruction)
791 return instructions
792}
793
794// Convenience function to generare ofp_flow_mod message with OXM BASIC match composed from the match_fields, and
795// single APPLY_ACTIONS instruction with a list if ofp_action objects.
796func MkSimpleFlowMod(matchFields []*ofp.OfpOxmField, actions []*ofp.OfpAction, command *ofp.OfpFlowModCommand, kw OfpFlowModArgs) *ofp.OfpFlowMod {
797
798 // Process actions instructions
799 instructions := make([]*ofp.OfpInstruction, 0)
800 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
801 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
802 instructions = append(instructions, &instruction)
803
804 // Process next table
805 if tableId := GetNextTableId(kw); tableId != nil {
806 var instGotoTable ofp.OfpInstruction_GotoTable
807 instGotoTable.GotoTable = &ofp.OfpInstructionGotoTable{TableId: *tableId}
808 inst := ofp.OfpInstruction{Type: uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE), Data: &instGotoTable}
809 instructions = append(instructions, &inst)
810 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400811 // Process meter action
812 if meterId := GetMeterIdFlowModArgs(kw); meterId != 0 {
813 var instMeter ofp.OfpInstruction_Meter
814 instMeter.Meter = &ofp.OfpInstructionMeter{MeterId: meterId}
815 inst := ofp.OfpInstruction{Type: uint32(METER_ACTION), Data: &instMeter}
816 instructions = append(instructions, &inst)
817 }
818 //process write_metadata action
819 if metadata := GetMetadataFlowModArgs(kw); metadata != 0 {
820 var instWriteMetadata ofp.OfpInstruction_WriteMetadata
821 instWriteMetadata.WriteMetadata = &ofp.OfpInstructionWriteMetadata{Metadata: metadata}
822 inst := ofp.OfpInstruction{Type: uint32(WRITE_METADATA), Data: &instWriteMetadata}
823 instructions = append(instructions, &inst)
824 }
khenaidoo68c930b2019-05-13 11:46:51 -0400825
826 // Process match fields
827 oxmFields := make([]*ofp.OfpOxmField, 0)
828 for _, matchField := range matchFields {
829 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
830 oxmFields = append(oxmFields, &oxmField)
831 }
832 var match ofp.OfpMatch
833 match.Type = ofp.OfpMatchType_OFPMT_OXM
834 match.OxmFields = oxmFields
835
836 // Create ofp_flow_message
837 msg := &ofp.OfpFlowMod{}
838 if command == nil {
839 msg.Command = ofp.OfpFlowModCommand_OFPFC_ADD
840 } else {
841 msg.Command = *command
842 }
843 msg.Instructions = instructions
844 msg.Match = &match
845
846 // Set the variadic argument values
847 msg = setVariadicModAttributes(msg, kw)
848
849 return msg
850}
851
852func MkMulticastGroupMod(groupId uint32, buckets []*ofp.OfpBucket, command *ofp.OfpGroupModCommand) *ofp.OfpGroupMod {
853 group := &ofp.OfpGroupMod{}
854 if command == nil {
855 group.Command = ofp.OfpGroupModCommand_OFPGC_ADD
856 } else {
857 group.Command = *command
858 }
859 group.Type = ofp.OfpGroupType_OFPGT_ALL
860 group.GroupId = groupId
861 group.Buckets = buckets
862 return group
863}
864
865//SetVariadicModAttributes sets only uint64 or uint32 fields of the ofp_flow_mod message
866func setVariadicModAttributes(mod *ofp.OfpFlowMod, args OfpFlowModArgs) *ofp.OfpFlowMod {
867 if args == nil {
868 return mod
869 }
870 for key, val := range args {
871 switch key {
872 case "cookie":
873 mod.Cookie = val
874 case "cookie_mask":
875 mod.CookieMask = val
876 case "table_id":
877 mod.TableId = uint32(val)
878 case "idle_timeout":
879 mod.IdleTimeout = uint32(val)
880 case "hard_timeout":
881 mod.HardTimeout = uint32(val)
882 case "priority":
883 mod.Priority = uint32(val)
884 case "buffer_id":
885 mod.BufferId = uint32(val)
886 case "out_port":
887 mod.OutPort = uint32(val)
888 case "out_group":
889 mod.OutGroup = uint32(val)
890 case "flags":
891 mod.Flags = uint32(val)
892 }
893 }
894 return mod
895}
896
897func MkPacketIn(port uint32, packet []byte) *ofp.OfpPacketIn {
898 packetIn := &ofp.OfpPacketIn{
899 Reason: ofp.OfpPacketInReason_OFPR_ACTION,
900 Match: &ofp.OfpMatch{
901 Type: ofp.OfpMatchType_OFPMT_OXM,
902 OxmFields: []*ofp.OfpOxmField{
903 {
904 OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
905 Field: &ofp.OfpOxmField_OfbField{
906 OfbField: InPort(port)},
907 },
908 },
909 },
910 Data: packet,
911 }
912 return packetIn
913}
914
915// MkFlowStat is a helper method to build flows
916func MkFlowStat(fa *FlowArgs) *ofp.OfpFlowStats {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400917 //Build the match-fields
khenaidoo68c930b2019-05-13 11:46:51 -0400918 matchFields := make([]*ofp.OfpOxmField, 0)
919 for _, val := range fa.MatchFields {
920 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
921 }
922 return FlowStatsEntryFromFlowModMessage(MkSimpleFlowMod(matchFields, fa.Actions, fa.Command, fa.KV))
923}
924
925func MkGroupStat(ga *GroupArgs) *ofp.OfpGroupEntry {
926 return GroupEntryFromGroupMod(MkMulticastGroupMod(ga.GroupId, ga.Buckets, ga.Command))
927}
928
khenaidoo89b0e942018-10-21 21:11:33 -0400929type OfpFlowModArgs map[string]uint64
930
931type FlowArgs struct {
932 MatchFields []*ofp.OfpOxmOfbField
933 Actions []*ofp.OfpAction
934 Command *ofp.OfpFlowModCommand
935 Priority uint32
936 KV OfpFlowModArgs
937}
938
khenaidood20a5852018-10-22 22:09:55 -0400939type GroupArgs struct {
940 GroupId uint32
941 Buckets []*ofp.OfpBucket
942 Command *ofp.OfpGroupModCommand
943}
944
khenaidoo89b0e942018-10-21 21:11:33 -0400945type FlowsAndGroups struct {
946 Flows *ordered_map.OrderedMap
947 Groups *ordered_map.OrderedMap
948}
949
950func NewFlowsAndGroups() *FlowsAndGroups {
951 var fg FlowsAndGroups
952 fg.Flows = ordered_map.NewOrderedMap()
953 fg.Groups = ordered_map.NewOrderedMap()
954 return &fg
955}
956
957func (fg *FlowsAndGroups) Copy() *FlowsAndGroups {
958 copyFG := NewFlowsAndGroups()
959 iter := fg.Flows.IterFunc()
960 for kv, ok := iter(); ok; kv, ok = iter() {
961 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
962 copyFG.Flows.Set(kv.Key, proto.Clone(protoMsg))
963 }
964 }
965 iter = fg.Groups.IterFunc()
966 for kv, ok := iter(); ok; kv, ok = iter() {
967 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
968 copyFG.Groups.Set(kv.Key, proto.Clone(protoMsg))
969 }
970 }
971 return copyFG
972}
973
974func (fg *FlowsAndGroups) GetFlow(index int) *ofp.OfpFlowStats {
975 iter := fg.Flows.IterFunc()
976 pos := 0
977 for kv, ok := iter(); ok; kv, ok = iter() {
978 if pos == index {
979 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
980 return protoMsg
981 }
982 return nil
983 }
984 pos += 1
985 }
986 return nil
987}
988
khenaidoo19d7b632018-10-30 10:49:50 -0400989func (fg *FlowsAndGroups) ListFlows() []*ofp.OfpFlowStats {
990 flows := make([]*ofp.OfpFlowStats, 0)
991 iter := fg.Flows.IterFunc()
992 for kv, ok := iter(); ok; kv, ok = iter() {
993 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
994 flows = append(flows, protoMsg)
995 }
996 }
997 return flows
998}
999
1000func (fg *FlowsAndGroups) ListGroups() []*ofp.OfpGroupEntry {
1001 groups := make([]*ofp.OfpGroupEntry, 0)
1002 iter := fg.Groups.IterFunc()
1003 for kv, ok := iter(); ok; kv, ok = iter() {
1004 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1005 groups = append(groups, protoMsg)
1006 }
1007 }
1008 return groups
1009}
1010
khenaidoo89b0e942018-10-21 21:11:33 -04001011func (fg *FlowsAndGroups) String() string {
1012 var buffer bytes.Buffer
1013 iter := fg.Flows.IterFunc()
1014 for kv, ok := iter(); ok; kv, ok = iter() {
1015 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1016 buffer.WriteString("\nFlow:\n")
1017 buffer.WriteString(proto.MarshalTextString(protoMsg))
1018 buffer.WriteString("\n")
1019 }
1020 }
1021 iter = fg.Groups.IterFunc()
1022 for kv, ok := iter(); ok; kv, ok = iter() {
1023 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1024 buffer.WriteString("\nGroup:\n")
1025 buffer.WriteString(proto.MarshalTextString(protoMsg))
1026 buffer.WriteString("\n")
1027 }
1028 }
1029 return buffer.String()
1030}
1031
1032func (fg *FlowsAndGroups) AddFlow(flow *ofp.OfpFlowStats) {
khenaidoo68c930b2019-05-13 11:46:51 -04001033 if flow == nil {
1034 return
1035 }
1036
khenaidoo89b0e942018-10-21 21:11:33 -04001037 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 flow only if absent
1044 if _, exist := fg.Flows.Get(flow.Id); !exist {
1045 fg.Flows.Set(flow.Id, flow)
1046 }
1047}
1048
khenaidoo68c930b2019-05-13 11:46:51 -04001049func (fg *FlowsAndGroups) AddGroup(group *ofp.OfpGroupEntry) {
1050 if group == nil {
1051 return
1052 }
1053
1054 if fg.Flows == nil {
1055 fg.Flows = ordered_map.NewOrderedMap()
1056 }
1057 if fg.Groups == nil {
1058 fg.Groups = ordered_map.NewOrderedMap()
1059 }
1060 //Add group only if absent
1061 if _, exist := fg.Groups.Get(group.Desc.GroupId); !exist {
1062 fg.Groups.Set(group.Desc.GroupId, group)
1063 }
1064}
1065
khenaidoo89b0e942018-10-21 21:11:33 -04001066//AddFrom add flows and groups from the argument into this structure only if they do not already exist
1067func (fg *FlowsAndGroups) AddFrom(from *FlowsAndGroups) {
1068 iter := from.Flows.IterFunc()
1069 for kv, ok := iter(); ok; kv, ok = iter() {
1070 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1071 if _, exist := fg.Flows.Get(protoMsg.Id); !exist {
1072 fg.Flows.Set(protoMsg.Id, protoMsg)
1073 }
1074 }
1075 }
1076 iter = from.Groups.IterFunc()
1077 for kv, ok := iter(); ok; kv, ok = iter() {
1078 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1079 if _, exist := fg.Groups.Get(protoMsg.Stats.GroupId); !exist {
1080 fg.Groups.Set(protoMsg.Stats.GroupId, protoMsg)
1081 }
1082 }
1083 }
1084}
1085
1086type DeviceRules struct {
1087 Rules map[string]*FlowsAndGroups
1088}
1089
1090func NewDeviceRules() *DeviceRules {
1091 var dr DeviceRules
1092 dr.Rules = make(map[string]*FlowsAndGroups)
1093 return &dr
1094}
1095
1096func (dr *DeviceRules) Copy() *DeviceRules {
1097 copyDR := NewDeviceRules()
manikkaraj k6c9689d2019-05-09 12:59:52 -04001098 if dr != nil {
1099 for key, val := range dr.Rules {
1100 if val != nil {
1101 copyDR.Rules[key] = val.Copy()
1102 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001103 }
khenaidoo89b0e942018-10-21 21:11:33 -04001104 }
1105 return copyDR
1106}
1107
khenaidoo19d7b632018-10-30 10:49:50 -04001108func (dr *DeviceRules) ClearFlows(deviceId string) {
1109 if _, exist := dr.Rules[deviceId]; exist {
1110 dr.Rules[deviceId].Flows = ordered_map.NewOrderedMap()
1111 }
1112}
1113
khenaidoo2c6a0992019-04-29 13:46:56 -04001114func (dr *DeviceRules) FilterRules(deviceIds map[string]string) *DeviceRules {
1115 filteredDR := NewDeviceRules()
1116 for key, val := range dr.Rules {
1117 if _, exist := deviceIds[key]; exist {
1118 filteredDR.Rules[key] = val.Copy()
1119 }
1120 }
1121 return filteredDR
1122}
1123
khenaidoo19d7b632018-10-30 10:49:50 -04001124func (dr *DeviceRules) AddFlow(deviceId string, flow *ofp.OfpFlowStats) {
1125 if _, exist := dr.Rules[deviceId]; !exist {
1126 dr.Rules[deviceId] = NewFlowsAndGroups()
1127 }
1128 dr.Rules[deviceId].AddFlow(flow)
1129}
1130
1131func (dr *DeviceRules) GetRules() map[string]*FlowsAndGroups {
1132 return dr.Rules
1133}
1134
khenaidoo89b0e942018-10-21 21:11:33 -04001135func (dr *DeviceRules) String() string {
1136 var buffer bytes.Buffer
1137 for key, value := range dr.Rules {
1138 buffer.WriteString("DeviceId:")
1139 buffer.WriteString(key)
1140 buffer.WriteString(value.String())
1141 buffer.WriteString("\n\n")
1142 }
1143 return buffer.String()
1144}
1145
1146func (dr *DeviceRules) AddFlowsAndGroup(deviceId string, fg *FlowsAndGroups) {
khenaidood20a5852018-10-22 22:09:55 -04001147 if _, ok := dr.Rules[deviceId]; !ok {
1148 dr.Rules[deviceId] = NewFlowsAndGroups()
1149 }
khenaidoo89b0e942018-10-21 21:11:33 -04001150 dr.Rules[deviceId] = fg
1151}
khenaidood20a5852018-10-22 22:09:55 -04001152
1153// CreateEntryIfNotExist creates a new deviceId in the Map if it does not exist and assigns an
1154// empty FlowsAndGroups to it. Otherwise, it does nothing.
1155func (dr *DeviceRules) CreateEntryIfNotExist(deviceId string) {
1156 if _, ok := dr.Rules[deviceId]; !ok {
1157 dr.Rules[deviceId] = NewFlowsAndGroups()
1158 }
1159}
khenaidoo19d7b632018-10-30 10:49:50 -04001160
1161/*
1162 * Common flow routines
1163 */
1164
1165//FindOverlappingFlows return a list of overlapping flow(s) where mod is the flow request
1166func FindOverlappingFlows(flows []*ofp.OfpFlowStats, mod *ofp.OfpFlowMod) []*ofp.OfpFlowStats {
1167 return nil //TODO - complete implementation
1168}
1169
1170// FindFlowById returns the index of the flow in the flows array if present. Otherwise, it returns -1
1171func FindFlowById(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
1172 for idx, f := range flows {
1173 if flow.Id == f.Id {
1174 return idx
1175 }
1176 }
1177 return -1
1178}
1179
1180// FindFlows returns the index in flows where flow if present. Otherwise, it returns -1
1181func FindFlows(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
1182 for idx, f := range flows {
1183 if FlowMatch(f, flow) {
1184 return idx
1185 }
1186 }
1187 return -1
1188}
1189
1190//FlowMatch returns true if two flows matches on the following flow attributes:
1191//TableId, Priority, Flags, Cookie, Match
1192func FlowMatch(f1 *ofp.OfpFlowStats, f2 *ofp.OfpFlowStats) bool {
khenaidoo68c930b2019-05-13 11:46:51 -04001193 if f1 == nil || f2 == nil {
1194 return false
1195 }
khenaidoo19d7b632018-10-30 10:49:50 -04001196 keysMatter := []string{"TableId", "Priority", "Flags", "Cookie", "Match"}
1197 for _, key := range keysMatter {
1198 switch key {
1199 case "TableId":
1200 if f1.TableId != f2.TableId {
1201 return false
1202 }
1203 case "Priority":
1204 if f1.Priority != f2.Priority {
1205 return false
1206 }
1207 case "Flags":
1208 if f1.Flags != f2.Flags {
1209 return false
1210 }
1211 case "Cookie":
1212 if f1.Cookie != f2.Cookie {
1213 return false
1214 }
1215 case "Match":
1216 if strings.Compare(f1.Match.String(), f2.Match.String()) != 0 {
1217 return false
1218 }
1219 }
1220 }
1221 return true
1222}
1223
1224//FlowMatchesMod returns True if given flow is "covered" by the wildcard flow_mod, taking into consideration of
1225//both exact matches as well as masks-based match fields if any. Otherwise return False
1226func FlowMatchesMod(flow *ofp.OfpFlowStats, mod *ofp.OfpFlowMod) bool {
khenaidoo68c930b2019-05-13 11:46:51 -04001227 if flow == nil || mod == nil {
1228 return false
1229 }
khenaidoo19d7b632018-10-30 10:49:50 -04001230 //Check if flow.cookie is covered by mod.cookie and mod.cookie_mask
1231 if (flow.Cookie & mod.CookieMask) != (mod.Cookie & mod.CookieMask) {
1232 return false
1233 }
1234
1235 //Check if flow.table_id is covered by flow_mod.table_id
1236 if mod.TableId != uint32(ofp.OfpTable_OFPTT_ALL) && flow.TableId != mod.TableId {
1237 return false
1238 }
1239
1240 //Check out_port
1241 if (mod.OutPort&0x7fffffff) != uint32(ofp.OfpPortNo_OFPP_ANY) && !FlowHasOutPort(flow, mod.OutPort) {
1242 return false
1243 }
1244
1245 // Check out_group
1246 if (mod.OutGroup&0x7fffffff) != uint32(ofp.OfpGroup_OFPG_ANY) && !FlowHasOutGroup(flow, mod.OutGroup) {
1247 return false
1248 }
1249
1250 //Priority is ignored
1251
1252 //Check match condition
1253 //If the flow_mod match field is empty, that is a special case and indicates the flow entry matches
khenaidoo0458db62019-06-20 08:50:36 -04001254 if (mod.Match == nil) || (mod.Match.OxmFields == nil) || (len(mod.Match.OxmFields) == 0) {
khenaidoo19d7b632018-10-30 10:49:50 -04001255 //If we got this far and the match is empty in the flow spec, than the flow matches
1256 return true
1257 } // TODO : implement the flow match analysis
1258 return false
1259
1260}
1261
1262//FlowHasOutPort returns True if flow has a output command with the given out_port
1263func FlowHasOutPort(flow *ofp.OfpFlowStats, outPort uint32) bool {
khenaidoo68c930b2019-05-13 11:46:51 -04001264 if flow == nil {
1265 return false
1266 }
khenaidoo19d7b632018-10-30 10:49:50 -04001267 for _, instruction := range flow.Instructions {
1268 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
1269 if instruction.GetActions() == nil {
1270 return false
1271 }
1272 for _, action := range instruction.GetActions().Actions {
1273 if action.Type == ofp.OfpActionType_OFPAT_OUTPUT {
1274 if (action.GetOutput() != nil) && (action.GetOutput().Port == outPort) {
1275 return true
1276 }
1277 }
1278
1279 }
1280 }
1281 }
1282 return false
1283}
1284
1285//FlowHasOutGroup return True if flow has a output command with the given out_group
1286func FlowHasOutGroup(flow *ofp.OfpFlowStats, groupID uint32) bool {
khenaidoo68c930b2019-05-13 11:46:51 -04001287 if flow == nil {
1288 return false
1289 }
khenaidoo19d7b632018-10-30 10:49:50 -04001290 for _, instruction := range flow.Instructions {
1291 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
1292 if instruction.GetActions() == nil {
1293 return false
1294 }
1295 for _, action := range instruction.GetActions().Actions {
1296 if action.Type == ofp.OfpActionType_OFPAT_GROUP {
1297 if (action.GetGroup() != nil) && (action.GetGroup().GroupId == groupID) {
1298 return true
1299 }
1300 }
1301
1302 }
1303 }
1304 }
1305 return false
1306}
1307
1308//FindGroup returns index of group if found, else returns -1
1309func FindGroup(groups []*ofp.OfpGroupEntry, groupId uint32) int {
1310 for idx, group := range groups {
1311 if group.Desc.GroupId == groupId {
1312 return idx
1313 }
1314 }
1315 return -1
1316}
1317
1318func FlowsDeleteByGroupId(flows []*ofp.OfpFlowStats, groupId uint32) (bool, []*ofp.OfpFlowStats) {
1319 toKeep := make([]*ofp.OfpFlowStats, 0)
1320
1321 for _, f := range flows {
1322 if !FlowHasOutGroup(f, groupId) {
1323 toKeep = append(toKeep, f)
1324 }
1325 }
1326 return len(toKeep) < len(flows), toKeep
1327}
khenaidoo0458db62019-06-20 08:50:36 -04001328
1329func ToOfpOxmField(from []*ofp.OfpOxmOfbField) []*ofp.OfpOxmField {
1330 matchFields := make([]*ofp.OfpOxmField, 0)
1331 for _, val := range from {
1332 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
1333 }
1334 return matchFields
1335}
Scott Baker973f8ba2019-11-19 15:00:22 -08001336
1337//IsMulticastIp returns true if the ip starts with the byte sequence of 1110;
1338//false otherwise.
1339func IsMulticastIp(ip uint32) bool {
1340 return ip>>28 == 14
1341}
1342
1343//ConvertToMulticastMacInt returns equivalent mac address of the given multicast ip address
1344func ConvertToMulticastMacInt(ip uint32) uint64 {
1345 //get last 23 bits of ip address by ip & 00000000011111111111111111111111
1346 theLast23BitsOfIp := ip & 8388607
1347 // perform OR with 0x1005E000000 to build mcast mac address
1348 return 1101088686080 | uint64(theLast23BitsOfIp)
1349}
1350
1351//ConvertToMulticastMacBytes returns equivalent mac address of the given multicast ip address
1352func ConvertToMulticastMacBytes(ip uint32) []byte {
1353 mac := ConvertToMulticastMacInt(ip)
1354 var b bytes.Buffer
1355 // catalyze (48 bits) in binary:111111110000000000000000000000000000000000000000
1356 catalyze := uint64(280375465082880)
1357 //convert each octet to decimal
1358 for i := 0; i < 6; i++ {
1359 if i != 0 {
1360 catalyze = catalyze >> 8
1361 }
1362 octet := mac & catalyze
1363 octetDecimal := octet >> uint8(40-i*8)
1364 b.WriteByte(byte(octetDecimal))
1365 }
1366 return b.Bytes()
1367}