blob: f7026336dbc0b87648bd0829af98eb27d5007cf2 [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 */
16
17package flow_decomposition
18
19import (
20 "bytes"
21 "crypto/md5"
22 "fmt"
khenaidoo19d7b632018-10-30 10:49:50 -040023 "github.com/gogo/protobuf/proto"
khenaidoo89b0e942018-10-21 21:11:33 -040024 "github.com/opencord/voltha-go/common/log"
25 ofp "github.com/opencord/voltha-go/protos/openflow_13"
26 "github.com/opencord/voltha-go/protos/voltha"
27 "github.com/opencord/voltha-go/rw_core/coreIf"
28 "github.com/opencord/voltha-go/rw_core/graph"
29 fu "github.com/opencord/voltha-go/rw_core/utils"
30 "math/big"
31)
32
33func init() {
34 log.AddPackage(log.JSON, log.DebugLevel, nil)
35}
36
37var (
38 // Instructions shortcut
39 APPLY_ACTIONS = ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS
40
41 //OFPAT_* shortcuts
42 OUTPUT = ofp.OfpActionType_OFPAT_OUTPUT
43 COPY_TTL_OUT = ofp.OfpActionType_OFPAT_COPY_TTL_OUT
44 COPY_TTL_IN = ofp.OfpActionType_OFPAT_COPY_TTL_IN
45 SET_MPLS_TTL = ofp.OfpActionType_OFPAT_SET_MPLS_TTL
46 DEC_MPLS_TTL = ofp.OfpActionType_OFPAT_DEC_MPLS_TTL
47 PUSH_VLAN = ofp.OfpActionType_OFPAT_PUSH_VLAN
48 POP_VLAN = ofp.OfpActionType_OFPAT_POP_VLAN
49 PUSH_MPLS = ofp.OfpActionType_OFPAT_PUSH_MPLS
50 POP_MPLS = ofp.OfpActionType_OFPAT_POP_MPLS
51 SET_QUEUE = ofp.OfpActionType_OFPAT_SET_QUEUE
52 GROUP = ofp.OfpActionType_OFPAT_GROUP
53 SET_NW_TTL = ofp.OfpActionType_OFPAT_SET_NW_TTL
54 NW_TTL = ofp.OfpActionType_OFPAT_DEC_NW_TTL
55 SET_FIELD = ofp.OfpActionType_OFPAT_SET_FIELD
56 PUSH_PBB = ofp.OfpActionType_OFPAT_PUSH_PBB
57 POP_PBB = ofp.OfpActionType_OFPAT_POP_PBB
58 EXPERIMENTER = ofp.OfpActionType_OFPAT_EXPERIMENTER
59
60 //OFPXMT_OFB_* shortcuts (incomplete)
61 IN_PORT = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT
62 IN_PHY_PORT = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT
63 METADATA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_METADATA
64 ETH_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_DST
65 ETH_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_SRC
66 ETH_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE
67 VLAN_VID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID
68 VLAN_PCP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP
69 IP_DSCP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_DSCP
70 IP_ECN = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_ECN
71 IP_PROTO = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO
72 IPV4_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_SRC
73 IPV4_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST
74 TCP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TCP_SRC
75 TCP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TCP_DST
76 UDP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC
77 UDP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST
78 SCTP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_SCTP_SRC
79 SCTP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_SCTP_DST
80 ICMPV4_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV4_TYPE
81 ICMPV4_CODE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV4_CODE
82 ARP_OP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_OP
83 ARP_SPA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_SPA
84 ARP_TPA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_TPA
85 ARP_SHA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_SHA
86 ARP_THA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_THA
87 IPV6_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_SRC
88 IPV6_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_DST
89 IPV6_FLABEL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_FLABEL
90 ICMPV6_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV6_TYPE
91 ICMPV6_CODE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV6_CODE
92 IPV6_ND_TARGET = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_TARGET
93 OFB_IPV6_ND_SLL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_SLL
94 IPV6_ND_TLL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_TLL
95 MPLS_LABEL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_LABEL
96 MPLS_TC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_TC
97 MPLS_BOS = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_BOS
98 PBB_ISID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_PBB_ISID
99 TUNNEL_ID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TUNNEL_ID
100 IPV6_EXTHDR = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_EXTHDR
101)
102
103//ofp_action_* shortcuts
104
105func Output(port uint32, maxLen ...ofp.OfpControllerMaxLen) *ofp.OfpAction {
106 maxLength := ofp.OfpControllerMaxLen_OFPCML_MAX
107 if len(maxLen) > 0 {
108 maxLength = maxLen[0]
109 }
110 return &ofp.OfpAction{Type: OUTPUT, Action: &ofp.OfpAction_Output{Output: &ofp.OfpActionOutput{Port: port, MaxLen: uint32(maxLength)}}}
111}
112
113func MplsTtl(ttl uint32) *ofp.OfpAction {
114 return &ofp.OfpAction{Type: SET_MPLS_TTL, Action: &ofp.OfpAction_MplsTtl{MplsTtl: &ofp.OfpActionMplsTtl{MplsTtl: ttl}}}
115}
116
117func PushVlan(ethType uint32) *ofp.OfpAction {
118 return &ofp.OfpAction{Type: PUSH_VLAN, Action: &ofp.OfpAction_Push{Push: &ofp.OfpActionPush{Ethertype: ethType}}}
119}
120
121func PopVlan() *ofp.OfpAction {
122 return &ofp.OfpAction{Type: POP_VLAN}
123}
124
125func PopMpls(ethType uint32) *ofp.OfpAction {
126 return &ofp.OfpAction{Type: POP_MPLS, Action: &ofp.OfpAction_PopMpls{PopMpls: &ofp.OfpActionPopMpls{Ethertype: ethType}}}
127}
128
129func Group(groupId uint32) *ofp.OfpAction {
130 return &ofp.OfpAction{Type: GROUP, Action: &ofp.OfpAction_Group{Group: &ofp.OfpActionGroup{GroupId: groupId}}}
131}
132
133func NwTtl(nwTtl uint32) *ofp.OfpAction {
134 return &ofp.OfpAction{Type: NW_TTL, Action: &ofp.OfpAction_NwTtl{NwTtl: &ofp.OfpActionNwTtl{NwTtl: nwTtl}}}
135}
136
137func SetField(field *ofp.OfpOxmOfbField) *ofp.OfpAction {
138 actionSetField := &ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: &ofp.OfpOxmField_OfbField{OfbField: field}}
139 return &ofp.OfpAction{Type: SET_FIELD, Action: &ofp.OfpAction_SetField{SetField: &ofp.OfpActionSetField{Field: actionSetField}}}
140}
141
142func Experimenter(experimenter uint32, data []byte) *ofp.OfpAction {
143 return &ofp.OfpAction{Type: EXPERIMENTER, Action: &ofp.OfpAction_Experimenter{Experimenter: &ofp.OfpActionExperimenter{Experimenter: experimenter, Data: data}}}
144}
145
146//ofb_field generators (incomplete set)
147
148func InPort(inPort uint32) *ofp.OfpOxmOfbField {
149 return &ofp.OfpOxmOfbField{Type: IN_PORT, Value: &ofp.OfpOxmOfbField_Port{Port: inPort}}
150}
151
152func InPhyPort(inPhyPort uint32) *ofp.OfpOxmOfbField {
153 return &ofp.OfpOxmOfbField{Type: IN_PHY_PORT, Value: &ofp.OfpOxmOfbField_Port{Port: inPhyPort}}
154}
155
156func Metadata_ofp(tableMetadata uint64) *ofp.OfpOxmOfbField {
157 return &ofp.OfpOxmOfbField{Type: METADATA, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: tableMetadata}}
158}
159
160// should Metadata_ofp used here ?????
161func EthDst(ethDst uint64) *ofp.OfpOxmOfbField {
162 return &ofp.OfpOxmOfbField{Type: ETH_DST, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: ethDst}}
163}
164
165// should Metadata_ofp used here ?????
166func EthSrc(ethSrc uint64) *ofp.OfpOxmOfbField {
167 return &ofp.OfpOxmOfbField{Type: ETH_SRC, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: ethSrc}}
168}
169
170func EthType(ethType uint32) *ofp.OfpOxmOfbField {
171 return &ofp.OfpOxmOfbField{Type: ETH_TYPE, Value: &ofp.OfpOxmOfbField_EthType{EthType: ethType}}
172}
173
174func VlanVid(vlanVid uint32) *ofp.OfpOxmOfbField {
175 return &ofp.OfpOxmOfbField{Type: VLAN_VID, Value: &ofp.OfpOxmOfbField_VlanVid{VlanVid: vlanVid}}
176}
177
178func VlanPcp(vlanPcp uint32) *ofp.OfpOxmOfbField {
khenaidoo19d7b632018-10-30 10:49:50 -0400179 return &ofp.OfpOxmOfbField{Type: VLAN_PCP, Value: &ofp.OfpOxmOfbField_VlanPcp{VlanPcp: vlanPcp}}
khenaidoo89b0e942018-10-21 21:11:33 -0400180}
181
182func IpDscp(ipDscp uint32) *ofp.OfpOxmOfbField {
183 return &ofp.OfpOxmOfbField{Type: IP_DSCP, Value: &ofp.OfpOxmOfbField_IpDscp{IpDscp: ipDscp}}
184}
185
186func IpEcn(ipEcn uint32) *ofp.OfpOxmOfbField {
187 return &ofp.OfpOxmOfbField{Type: IP_ECN, Value: &ofp.OfpOxmOfbField_IpEcn{IpEcn: ipEcn}}
188}
189
190func IpProto(ipProto uint32) *ofp.OfpOxmOfbField {
191 return &ofp.OfpOxmOfbField{Type: IP_PROTO, Value: &ofp.OfpOxmOfbField_IpProto{IpProto: ipProto}}
192}
193
194func Ipv4Src(ipv4Src uint32) *ofp.OfpOxmOfbField {
195 return &ofp.OfpOxmOfbField{Type: IPV4_SRC, Value: &ofp.OfpOxmOfbField_Ipv4Src{Ipv4Src: ipv4Src}}
196}
197
198func Ipv4Dst(ipv4Dst uint32) *ofp.OfpOxmOfbField {
199 return &ofp.OfpOxmOfbField{Type: IPV4_DST, Value: &ofp.OfpOxmOfbField_Ipv4Dst{Ipv4Dst: ipv4Dst}}
200}
201
202func TcpSrc(tcpSrc uint32) *ofp.OfpOxmOfbField {
203 return &ofp.OfpOxmOfbField{Type: TCP_SRC, Value: &ofp.OfpOxmOfbField_TcpSrc{TcpSrc: tcpSrc}}
204}
205
206func TcpDst(tcpDst uint32) *ofp.OfpOxmOfbField {
207 return &ofp.OfpOxmOfbField{Type: TCP_DST, Value: &ofp.OfpOxmOfbField_TcpDst{TcpDst: tcpDst}}
208}
209
210func UdpSrc(udpSrc uint32) *ofp.OfpOxmOfbField {
211 return &ofp.OfpOxmOfbField{Type: UDP_SRC, Value: &ofp.OfpOxmOfbField_UdpSrc{UdpSrc: udpSrc}}
212}
213
214func UdpDst(udpDst uint32) *ofp.OfpOxmOfbField {
215 return &ofp.OfpOxmOfbField{Type: UDP_DST, Value: &ofp.OfpOxmOfbField_UdpDst{UdpDst: udpDst}}
216}
217
218func SctpSrc(sctpSrc uint32) *ofp.OfpOxmOfbField {
219 return &ofp.OfpOxmOfbField{Type: SCTP_SRC, Value: &ofp.OfpOxmOfbField_SctpSrc{SctpSrc: sctpSrc}}
220}
221
222func SctpDst(sctpDst uint32) *ofp.OfpOxmOfbField {
223 return &ofp.OfpOxmOfbField{Type: SCTP_DST, Value: &ofp.OfpOxmOfbField_SctpDst{SctpDst: sctpDst}}
224}
225
226func Icmpv4Type(icmpv4Type uint32) *ofp.OfpOxmOfbField {
227 return &ofp.OfpOxmOfbField{Type: ICMPV4_TYPE, Value: &ofp.OfpOxmOfbField_Icmpv4Type{Icmpv4Type: icmpv4Type}}
228}
229
230func Icmpv4Code(icmpv4Code uint32) *ofp.OfpOxmOfbField {
231 return &ofp.OfpOxmOfbField{Type: ICMPV4_CODE, Value: &ofp.OfpOxmOfbField_Icmpv4Code{Icmpv4Code: icmpv4Code}}
232}
233
234func ArpOp(arpOp uint32) *ofp.OfpOxmOfbField {
235 return &ofp.OfpOxmOfbField{Type: ARP_OP, Value: &ofp.OfpOxmOfbField_ArpOp{ArpOp: arpOp}}
236}
237
238func ArpSpa(arpSpa uint32) *ofp.OfpOxmOfbField {
239 return &ofp.OfpOxmOfbField{Type: ARP_SPA, Value: &ofp.OfpOxmOfbField_ArpSpa{ArpSpa: arpSpa}}
240}
241
242func ArpTpa(arpTpa uint32) *ofp.OfpOxmOfbField {
243 return &ofp.OfpOxmOfbField{Type: ARP_TPA, Value: &ofp.OfpOxmOfbField_ArpTpa{ArpTpa: arpTpa}}
244}
245
246func ArpSha(arpSha []byte) *ofp.OfpOxmOfbField {
247 return &ofp.OfpOxmOfbField{Type: ARP_SHA, Value: &ofp.OfpOxmOfbField_ArpSha{ArpSha: arpSha}}
248}
249
250func ArpTha(arpTha []byte) *ofp.OfpOxmOfbField {
251 return &ofp.OfpOxmOfbField{Type: ARP_THA, Value: &ofp.OfpOxmOfbField_ArpTha{ArpTha: arpTha}}
252}
253
254func Ipv6Src(ipv6Src []byte) *ofp.OfpOxmOfbField {
255 return &ofp.OfpOxmOfbField{Type: IPV6_SRC, Value: &ofp.OfpOxmOfbField_Ipv6Src{Ipv6Src: ipv6Src}}
256}
257
258func Ipv6Dst(ipv6Dst []byte) *ofp.OfpOxmOfbField {
259 return &ofp.OfpOxmOfbField{Type: IPV6_DST, Value: &ofp.OfpOxmOfbField_Ipv6Dst{Ipv6Dst: ipv6Dst}}
260}
261
262func Ipv6Flabel(ipv6Flabel uint32) *ofp.OfpOxmOfbField {
263 return &ofp.OfpOxmOfbField{Type: IPV6_FLABEL, Value: &ofp.OfpOxmOfbField_Ipv6Flabel{Ipv6Flabel: ipv6Flabel}}
264}
265
266func Icmpv6Type(icmpv6Type uint32) *ofp.OfpOxmOfbField {
267 return &ofp.OfpOxmOfbField{Type: ICMPV6_TYPE, Value: &ofp.OfpOxmOfbField_Icmpv6Type{Icmpv6Type: icmpv6Type}}
268}
269
270func Icmpv6Code(icmpv6Code uint32) *ofp.OfpOxmOfbField {
271 return &ofp.OfpOxmOfbField{Type: ICMPV6_CODE, Value: &ofp.OfpOxmOfbField_Icmpv6Code{Icmpv6Code: icmpv6Code}}
272}
273
274func Ipv6NdTarget(ipv6NdTarget []byte) *ofp.OfpOxmOfbField {
275 return &ofp.OfpOxmOfbField{Type: IPV6_ND_TARGET, Value: &ofp.OfpOxmOfbField_Ipv6NdTarget{Ipv6NdTarget: ipv6NdTarget}}
276}
277
278func OfbIpv6NdSll(ofbIpv6NdSll []byte) *ofp.OfpOxmOfbField {
279 return &ofp.OfpOxmOfbField{Type: OFB_IPV6_ND_SLL, Value: &ofp.OfpOxmOfbField_Ipv6NdSsl{Ipv6NdSsl: ofbIpv6NdSll}}
280}
281
282func Ipv6NdTll(ipv6NdTll []byte) *ofp.OfpOxmOfbField {
283 return &ofp.OfpOxmOfbField{Type: IPV6_ND_TLL, Value: &ofp.OfpOxmOfbField_Ipv6NdTll{Ipv6NdTll: ipv6NdTll}}
284}
285
286func MplsLabel(mplsLabel uint32) *ofp.OfpOxmOfbField {
287 return &ofp.OfpOxmOfbField{Type: MPLS_LABEL, Value: &ofp.OfpOxmOfbField_MplsLabel{MplsLabel: mplsLabel}}
288}
289
290func MplsTc(mplsTc uint32) *ofp.OfpOxmOfbField {
291 return &ofp.OfpOxmOfbField{Type: MPLS_TC, Value: &ofp.OfpOxmOfbField_MplsTc{MplsTc: mplsTc}}
292}
293
294func MplsBos(mplsBos uint32) *ofp.OfpOxmOfbField {
295 return &ofp.OfpOxmOfbField{Type: MPLS_BOS, Value: &ofp.OfpOxmOfbField_MplsBos{MplsBos: mplsBos}}
296}
297
298func PbbIsid(pbbIsid uint32) *ofp.OfpOxmOfbField {
299 return &ofp.OfpOxmOfbField{Type: PBB_ISID, Value: &ofp.OfpOxmOfbField_PbbIsid{PbbIsid: pbbIsid}}
300}
301
302func TunnelId(tunnelId uint64) *ofp.OfpOxmOfbField {
303 return &ofp.OfpOxmOfbField{Type: TUNNEL_ID, Value: &ofp.OfpOxmOfbField_TunnelId{TunnelId: tunnelId}}
304}
305
306func Ipv6Exthdr(ipv6Exthdr uint32) *ofp.OfpOxmOfbField {
307 return &ofp.OfpOxmOfbField{Type: IPV6_EXTHDR, Value: &ofp.OfpOxmOfbField_Ipv6Exthdr{Ipv6Exthdr: ipv6Exthdr}}
308}
309
310//frequently used extractors
311
khenaidood20a5852018-10-22 22:09:55 -0400312func excludeAction(action *ofp.OfpAction, exclude ...ofp.OfpActionType) bool {
313 for _, actionToExclude := range exclude {
314 if action.Type == actionToExclude {
315 return true
316 }
317 }
318 return false
319}
320
321func GetActions(flow *ofp.OfpFlowStats, exclude ...ofp.OfpActionType) []*ofp.OfpAction {
khenaidoo89b0e942018-10-21 21:11:33 -0400322 if flow == nil {
323 return nil
324 }
325 for _, instruction := range flow.Instructions {
326 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
327 instActions := instruction.GetActions()
328 if instActions == nil {
329 return nil
330 }
khenaidood20a5852018-10-22 22:09:55 -0400331 if len(exclude) == 0 {
332 return instActions.Actions
333 } else {
334 filteredAction := make([]*ofp.OfpAction, 0)
335 for _, action := range instActions.Actions {
336 if !excludeAction(action, exclude...) {
337 filteredAction = append(filteredAction, action)
338 }
339 }
340 return filteredAction
341 }
khenaidoo89b0e942018-10-21 21:11:33 -0400342 }
343 }
344 return nil
345}
346
khenaidoo19d7b632018-10-30 10:49:50 -0400347func UpdateOutputPortByActionType(flow *ofp.OfpFlowStats, actionType uint32, toPort uint32) *ofp.OfpFlowStats {
348 if flow == nil {
349 return nil
350 }
351 nFlow := (proto.Clone(flow)).(*ofp.OfpFlowStats)
352 nFlow.Instructions = nil
353 nInsts := make([]*ofp.OfpInstruction, 0)
354 for _, instruction := range flow.Instructions {
355 if instruction.Type == actionType {
356 instActions := instruction.GetActions()
357 if instActions == nil {
358 return nil
359 }
360 nActions := make([]*ofp.OfpAction, 0)
361 for _, action := range instActions.Actions {
362 if action.GetOutput() != nil {
363 nActions = append(nActions, Output(toPort))
364 } else {
365 nActions = append(nActions, action)
366 }
367 }
368 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: nActions}}
369 nInsts = append(nInsts, &ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction})
370 } else {
371 nInsts = append(nInsts, instruction)
372 }
373 }
374 nFlow.Instructions = nInsts
375 return nFlow
376}
377
khenaidood20a5852018-10-22 22:09:55 -0400378func excludeOxmOfbField(field *ofp.OfpOxmOfbField, exclude ...ofp.OxmOfbFieldTypes) bool {
379 for _, fieldToExclude := range exclude {
380 if field.Type == fieldToExclude {
381 return true
382 }
383 }
384 return false
385}
386
387func GetOfbFields(flow *ofp.OfpFlowStats, exclude ...ofp.OxmOfbFieldTypes) []*ofp.OfpOxmOfbField {
khenaidoo89b0e942018-10-21 21:11:33 -0400388 if flow == nil || flow.Match == nil || flow.Match.Type != ofp.OfpMatchType_OFPMT_OXM {
389 return nil
390 }
391 ofbFields := make([]*ofp.OfpOxmOfbField, 0)
392 for _, field := range flow.Match.OxmFields {
393 if field.OxmClass == ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
394 ofbFields = append(ofbFields, field.GetOfbField())
395 }
396 }
khenaidood20a5852018-10-22 22:09:55 -0400397 if len(exclude) == 0 {
398 return ofbFields
399 } else {
400 filteredFields := make([]*ofp.OfpOxmOfbField, 0)
401 for _, ofbField := range ofbFields {
402 if !excludeOxmOfbField(ofbField, exclude...) {
403 filteredFields = append(filteredFields, ofbField)
404 }
405 }
406 return filteredFields
407 }
khenaidoo89b0e942018-10-21 21:11:33 -0400408}
409
khenaidoofdbad6e2018-11-06 22:26:38 -0500410func GetPacketOutPort(packet *ofp.OfpPacketOut) uint32 {
411 if packet == nil {
412 return 0
413 }
414 for _, action := range packet.GetActions() {
415 if action.Type == OUTPUT {
416 return action.GetOutput().Port
417 }
418 }
419 return 0
420}
421
khenaidoo89b0e942018-10-21 21:11:33 -0400422func GetOutPort(flow *ofp.OfpFlowStats) uint32 {
423 if flow == nil {
424 return 0
425 }
426 for _, action := range GetActions(flow) {
427 if action.Type == OUTPUT {
428 out := action.GetOutput()
429 if out == nil {
430 return 0
431 }
432 return out.GetPort()
433 }
434 }
435 return 0
436}
437
438func GetInPort(flow *ofp.OfpFlowStats) uint32 {
439 if flow == nil {
440 return 0
441 }
442 for _, field := range GetOfbFields(flow) {
443 if field.Type == IN_PORT {
444 return field.GetPort()
445 }
446 }
447 return 0
448}
449
450func GetGotoTableId(flow *ofp.OfpFlowStats) uint32 {
451 if flow == nil {
452 return 0
453 }
454 for _, instruction := range flow.Instructions {
455 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE) {
456 gotoTable := instruction.GetGotoTable()
457 if gotoTable == nil {
458 return 0
459 }
460 return gotoTable.GetTableId()
461 }
462 }
463 return 0
464}
465
466//GetMetaData - legacy get method (only want lower 32 bits)
467func GetMetaData(flow *ofp.OfpFlowStats) uint32 {
468 if flow == nil {
469 return 0
470 }
471 for _, field := range GetOfbFields(flow) {
472 if field.Type == METADATA {
473 return uint32(field.GetTableMetadata() & 0xffffffff)
474 }
475 }
476 return 0
477}
478
479func GetMetaData64Bit(flow *ofp.OfpFlowStats) uint64 {
480 if flow == nil {
481 return 0
482 }
483 for _, field := range GetOfbFields(flow) {
484 if field.Type == METADATA {
485 return field.GetTableMetadata()
486 }
487 }
488 return 0
489}
490
491// GetPortNumberFromMetadata retrieves the port number from the Metadata_ofp. The port number (UNI on ONU) is in the
492// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
493// a Metadata_ofp field
494func GetPortNumberFromMetadata(flow *ofp.OfpFlowStats) uint64 {
495 md := GetMetaData64Bit(flow)
496 if md == 0 {
497 return 0
498 }
499 if md <= 0xffffffff {
khenaidoo297cd252019-02-07 22:10:23 -0500500 log.Debugw("onos-upgrade-suggested", log.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
khenaidoo89b0e942018-10-21 21:11:33 -0400501 return md
502 }
503 return md & 0xffffffff
504}
505
506//GetInnerTagFromMetaData retrieves the inner tag from the Metadata_ofp. The port number (UNI on ONU) is in the
507// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
508//// a Metadata_ofp field
509func GetInnerTagFromMetaData(flow *ofp.OfpFlowStats) uint64 {
510 md := GetMetaData64Bit(flow)
511 if md == 0 {
512 return 0
513 }
514 if md <= 0xffffffff {
khenaidoo297cd252019-02-07 22:10:23 -0500515 log.Debugw("onos-upgrade-suggested", log.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
khenaidoo89b0e942018-10-21 21:11:33 -0400516 return md
517 }
518 return (md >> 32) & 0xffffffff
519}
520
521func HasNextTable(flow *ofp.OfpFlowStats) bool {
522 if flow == nil {
523 return false
524 }
525 return GetGotoTableId(flow) != 0
526}
527
528func GetGroup(flow *ofp.OfpFlowStats) uint32 {
529 if flow == nil {
530 return 0
531 }
532 for _, action := range GetActions(flow) {
533 if action.Type == GROUP {
534 grp := action.GetGroup()
535 if grp == nil {
536 return 0
537 }
538 return grp.GetGroupId()
539 }
540 }
541 return 0
542}
543
544func HasGroup(flow *ofp.OfpFlowStats) bool {
545 return GetGroup(flow) != 0
546}
547
548// GetNextTableId returns the next table ID if the "table_id" is present in the map, otherwise return nil
549func GetNextTableId(kw fu.OfpFlowModArgs) *uint32 {
550 if val, exist := kw["table_id"]; exist {
551 ret := uint32(val)
552 return &ret
553 }
554 return nil
555}
556
557// Return unique 64-bit integer hash for flow covering the following attributes:
558// 'table_id', 'priority', 'flags', 'cookie', 'match', '_instruction_string'
559func hashFlowStats(flow *ofp.OfpFlowStats) uint64 {
560 if flow == nil { // Should never happen
561 return 0
562 }
563 // Create string with the instructions field first
564 var instructionString bytes.Buffer
565 for _, instruction := range flow.Instructions {
566 instructionString.WriteString(instruction.String())
567 }
568 var flowString = fmt.Sprintf("%d%d%d%d%s%s", flow.TableId, flow.Priority, flow.Flags, flow.Cookie, flow.Match.String(), instructionString.String())
569 h := md5.New()
570 h.Write([]byte(flowString))
571 hash := big.NewInt(0)
572 hash.SetBytes(h.Sum(nil))
573 return hash.Uint64()
574}
575
576// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
577func FlowStatsEntryFromFlowModMessage(mod *ofp.OfpFlowMod) *ofp.OfpFlowStats {
578 flow := &ofp.OfpFlowStats{}
579 if mod == nil {
580 return flow
581 }
582 flow.TableId = mod.TableId
583 flow.Priority = mod.Priority
584 flow.IdleTimeout = mod.IdleTimeout
585 flow.HardTimeout = mod.HardTimeout
586 flow.Flags = mod.Flags
587 flow.Cookie = mod.Cookie
588 flow.Match = mod.Match
589 flow.Instructions = mod.Instructions
590 flow.Id = hashFlowStats(flow)
591 return flow
592}
593
594func GroupEntryFromGroupMod(mod *ofp.OfpGroupMod) *ofp.OfpGroupEntry {
595 group := &ofp.OfpGroupEntry{}
596 if mod == nil {
597 return group
598 }
599 group.Desc = &ofp.OfpGroupDesc{Type: mod.Type, GroupId: mod.GroupId, Buckets: mod.Buckets}
600 group.Stats = &ofp.OfpGroupStats{GroupId: mod.GroupId}
khenaidood20a5852018-10-22 22:09:55 -0400601 //TODO do we need to instantiate bucket bins?
khenaidoo89b0e942018-10-21 21:11:33 -0400602 return group
603}
604
605func MkOxmFields(matchFields []ofp.OfpOxmField) []*ofp.OfpOxmField {
606 oxmFields := make([]*ofp.OfpOxmField, 0)
607 for _, matchField := range matchFields {
608 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
609 oxmFields = append(oxmFields, &oxmField)
610 }
611 return oxmFields
612}
613
614func MkInstructionsFromActions(actions []*ofp.OfpAction) []*ofp.OfpInstruction {
615 instructions := make([]*ofp.OfpInstruction, 0)
616 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
617 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
618 instructions = append(instructions, &instruction)
619 return instructions
620}
621
622// Convenience function to generare ofp_flow_mod message with OXM BASIC match composed from the match_fields, and
623// single APPLY_ACTIONS instruction with a list if ofp_action objects.
624func MkSimpleFlowMod(matchFields []*ofp.OfpOxmField, actions []*ofp.OfpAction, command *ofp.OfpFlowModCommand, kw fu.OfpFlowModArgs) *ofp.OfpFlowMod {
625
626 // Process actions instructions
627 instructions := make([]*ofp.OfpInstruction, 0)
628 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
629 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
630 instructions = append(instructions, &instruction)
631
632 // Process next table
633 if tableId := GetNextTableId(kw); tableId != nil {
634 var instGotoTable ofp.OfpInstruction_GotoTable
635 instGotoTable.GotoTable = &ofp.OfpInstructionGotoTable{TableId: *tableId}
636 inst := ofp.OfpInstruction{Type: uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE), Data: &instGotoTable}
637 instructions = append(instructions, &inst)
638 }
639
640 // Process match fields
641 oxmFields := make([]*ofp.OfpOxmField, 0)
642 for _, matchField := range matchFields {
643 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
644 oxmFields = append(oxmFields, &oxmField)
645 }
646 var match ofp.OfpMatch
647 match.Type = ofp.OfpMatchType_OFPMT_OXM
648 match.OxmFields = oxmFields
649
650 // Create ofp_flow_message
651 msg := &ofp.OfpFlowMod{}
652 if command == nil {
653 msg.Command = ofp.OfpFlowModCommand_OFPFC_ADD
654 } else {
655 msg.Command = *command
656 }
657 msg.Instructions = instructions
658 msg.Match = &match
659
660 // Set the variadic argument values
661 msg = setVariadicModAttributes(msg, kw)
662
663 return msg
664}
665
666func MkMulticastGroupMod(groupId uint32, buckets []*ofp.OfpBucket, command *ofp.OfpGroupModCommand) *ofp.OfpGroupMod {
667 group := &ofp.OfpGroupMod{}
668 if command == nil {
669 group.Command = ofp.OfpGroupModCommand_OFPGC_ADD
670 } else {
671 group.Command = *command
672 }
673 group.Type = ofp.OfpGroupType_OFPGT_ALL
674 group.GroupId = groupId
675 group.Buckets = buckets
676 return group
677}
678
679//SetVariadicModAttributes sets only uint64 or uint32 fields of the ofp_flow_mod message
680func setVariadicModAttributes(mod *ofp.OfpFlowMod, args fu.OfpFlowModArgs) *ofp.OfpFlowMod {
681 if args == nil {
682 return mod
683 }
684 for key, val := range args {
685 switch key {
686 case "cookie":
687 mod.Cookie = val
688 case "cookie_mask":
689 mod.CookieMask = val
690 case "table_id":
691 mod.TableId = uint32(val)
692 case "idle_timeout":
693 mod.IdleTimeout = uint32(val)
694 case "hard_timeout":
695 mod.HardTimeout = uint32(val)
696 case "priority":
697 mod.Priority = uint32(val)
698 case "buffer_id":
699 mod.BufferId = uint32(val)
700 case "out_port":
701 mod.OutPort = uint32(val)
702 case "out_group":
703 mod.OutGroup = uint32(val)
704 case "flags":
705 mod.Flags = uint32(val)
706 }
707 }
708 return mod
709}
710
khenaidoofdbad6e2018-11-06 22:26:38 -0500711func MkPacketIn(port uint32, packet []byte) *ofp.OfpPacketIn {
712 packetIn := &ofp.OfpPacketIn{
713 Reason: ofp.OfpPacketInReason_OFPR_ACTION,
714 Match: &ofp.OfpMatch{
715 Type: ofp.OfpMatchType_OFPMT_OXM,
716 OxmFields: []*ofp.OfpOxmField{
717 {
khenaidoo43c82122018-11-22 18:38:28 -0500718 OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
khenaidoofdbad6e2018-11-06 22:26:38 -0500719 Field: &ofp.OfpOxmField_OfbField{
720 OfbField: InPort(port)},
721 },
722 },
723 },
khenaidoo43c82122018-11-22 18:38:28 -0500724 Data: packet,
khenaidoofdbad6e2018-11-06 22:26:38 -0500725 }
726 return packetIn
727}
728
khenaidoo89b0e942018-10-21 21:11:33 -0400729// MkFlowStat is a helper method to build flows
730func MkFlowStat(fa *fu.FlowArgs) *ofp.OfpFlowStats {
731 //Build the matchfields
732 matchFields := make([]*ofp.OfpOxmField, 0)
733 for _, val := range fa.MatchFields {
734 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
735 }
736 return FlowStatsEntryFromFlowModMessage(MkSimpleFlowMod(matchFields, fa.Actions, fa.Command, fa.KV))
737}
738
khenaidood20a5852018-10-22 22:09:55 -0400739func MkGroupStat(ga *fu.GroupArgs) *ofp.OfpGroupEntry {
740 return GroupEntryFromGroupMod(MkMulticastGroupMod(ga.GroupId, ga.Buckets, ga.Command))
khenaidoo89b0e942018-10-21 21:11:33 -0400741}
742
743type FlowDecomposer struct {
744 deviceMgr coreIf.DeviceManager
745}
746
747func NewFlowDecomposer(deviceMgr coreIf.DeviceManager) *FlowDecomposer {
748 var decomposer FlowDecomposer
749 decomposer.deviceMgr = deviceMgr
750 return &decomposer
751}
752
753//DecomposeRules decomposes per-device flows and flow-groups from the flows and groups defined on a logical device
754func (fd *FlowDecomposer) DecomposeRules(agent coreIf.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups) *fu.DeviceRules {
755 rules := agent.GetAllDefaultRules()
756 deviceRules := rules.Copy()
757
758 groupMap := make(map[uint32]*ofp.OfpGroupEntry)
759 for _, groupEntry := range groups.Items {
760 groupMap[groupEntry.Desc.GroupId] = groupEntry
761 }
762
763 var decomposedRules *fu.DeviceRules
764 for _, flow := range flows.Items {
765 decomposedRules = fd.decomposeFlow(agent, flow, groupMap)
766 for deviceId, flowAndGroups := range decomposedRules.Rules {
khenaidood20a5852018-10-22 22:09:55 -0400767 deviceRules.CreateEntryIfNotExist(deviceId)
khenaidoo89b0e942018-10-21 21:11:33 -0400768 deviceRules.Rules[deviceId].AddFrom(flowAndGroups)
769 }
770 }
771 return deviceRules
772}
773
khenaidoo19d7b632018-10-30 10:49:50 -0400774// Handles special case of any controller-bound flow for a parent device
775func (fd *FlowDecomposer) updateOutputPortForControllerBoundFlowForParentDevide(flow *ofp.OfpFlowStats,
776 dr *fu.DeviceRules) *fu.DeviceRules {
777 EAPOL := EthType(0x888e)
778 IGMP := IpProto(2)
779 UDP := IpProto(17)
780
781 newDeviceRules := dr.Copy()
782 // Check whether we are dealing with a parent device
783 for deviceId, fg := range dr.GetRules() {
784 if root, _ := fd.deviceMgr.IsRootDevice(deviceId); root {
785 newDeviceRules.ClearFlows(deviceId)
786 for i := 0; i < fg.Flows.Len(); i++ {
787 f := fg.GetFlow(i)
788 UpdateOutPortNo := false
789 for _, field := range GetOfbFields(f) {
790 UpdateOutPortNo = (field.String() == EAPOL.String())
791 UpdateOutPortNo = UpdateOutPortNo || (field.String() == IGMP.String())
792 UpdateOutPortNo = UpdateOutPortNo || (field.String() == UDP.String())
793 if UpdateOutPortNo {
794 break
795 }
796 }
797 if UpdateOutPortNo {
798 f = UpdateOutputPortByActionType(f, uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS),
799 uint32(ofp.OfpPortNo_OFPP_CONTROLLER))
800 }
801 // Update flow Id as a change in the instruction field will result in a new flow ID
802 f.Id = hashFlowStats(f)
803 newDeviceRules.AddFlow(deviceId, (proto.Clone(f)).(*ofp.OfpFlowStats))
804 }
805 }
806 }
807 return newDeviceRules
808}
809
khenaidood20a5852018-10-22 22:09:55 -0400810//processControllerBoundFlow decomposes trap flows
811func (fd *FlowDecomposer) processControllerBoundFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
812 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
813
khenaidoo89b0e942018-10-21 21:11:33 -0400814 log.Debugw("trap-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "flow": flow})
khenaidood20a5852018-10-22 22:09:55 -0400815 deviceRules := fu.NewDeviceRules()
816
817 egressHop := route[1]
818
khenaidoo89b0e942018-10-21 21:11:33 -0400819 fg := fu.NewFlowsAndGroups()
820 if agent.GetDeviceGraph().IsRootPort(inPortNo) {
821 log.Debug("trap-nni")
822 var fa *fu.FlowArgs
823 fa = &fu.FlowArgs{
824 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
825 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400826 InPort(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400827 },
828 Actions: GetActions(flow),
829 }
830 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400831 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400832 fg.AddFlow(MkFlowStat(fa))
833 } else {
834 // Trap flow for UNI port
835 log.Debug("trap-uni")
836
837 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
838 var inPorts []uint32
839 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400840 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400841 } else {
842 inPorts = []uint32{inPortNo}
843 }
844 for _, inputPort := range inPorts {
845 var fa *fu.FlowArgs
846 // Upstream flow
847 fa = &fu.FlowArgs{
848 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
849 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400850 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400851 VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | inputPort),
852 },
853 Actions: []*ofp.OfpAction{
854 PushVlan(0x8100),
855 SetField(VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
khenaidood20a5852018-10-22 22:09:55 -0400856 Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400857 },
858 }
859 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400860 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT, VLAN_VID)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400861 fg.AddFlow(MkFlowStat(fa))
862
863 // Downstream flow
864 fa = &fu.FlowArgs{
865 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority)},
866 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400867 InPort(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400868 VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000),
869 VlanPcp(0),
870 Metadata_ofp(uint64(inputPort)),
871 },
872 Actions: []*ofp.OfpAction{
873 PopVlan(),
khenaidood20a5852018-10-22 22:09:55 -0400874 Output(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400875 },
876 }
877 fg.AddFlow(MkFlowStat(fa))
878 }
879 }
khenaidood20a5852018-10-22 22:09:55 -0400880 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400881 return deviceRules
882}
883
884// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
885// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
886// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
887// applied at the OLT
khenaidood20a5852018-10-22 22:09:55 -0400888func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreIf.LogicalDeviceAgent,
889 route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
890
khenaidoo89b0e942018-10-21 21:11:33 -0400891 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400892 deviceRules := fu.NewDeviceRules()
893
894 ingressHop := route[0]
895 egressHop := route[1]
896
khenaidoo89b0e942018-10-21 21:11:33 -0400897 if HasNextTable(flow) {
898 log.Debugw("has-next-table", log.Fields{"table_id": flow.TableId})
899 if outPortNo != 0 {
900 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
901 }
902 var fa *fu.FlowArgs
903 fa = &fu.FlowArgs{
904 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
905 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400906 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400907 },
908 Actions: GetActions(flow),
909 }
910 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400911 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
912
913 // Augment the Actions
914 fa.Actions = append(fa.Actions, Output(ingressHop.Egress))
915
khenaidoo89b0e942018-10-21 21:11:33 -0400916 fg := fu.NewFlowsAndGroups()
917 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400918 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400919 } else {
920 var actions []ofp.OfpActionType
921 var isOutputTypeInActions bool
922 for _, action := range GetActions(flow) {
923 actions = append(actions, action.Type)
924 if !isOutputTypeInActions && action.Type == OUTPUT {
925 isOutputTypeInActions = true
926 }
927 }
928 if len(actions) == 1 && isOutputTypeInActions {
929 var fa *fu.FlowArgs
930 // child device flow
931 fa = &fu.FlowArgs{
932 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
933 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400934 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400935 },
936 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -0400937 Output(ingressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400938 },
939 }
940 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400941 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400942 fg := fu.NewFlowsAndGroups()
943 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400944 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400945
946 // parent device flow
947 fa = &fu.FlowArgs{
948 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
949 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400950 InPort(egressHop.Ingress), //egress_hop.ingress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400951 },
952 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -0400953 Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400954 },
955 }
956 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400957 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400958 fg = fu.NewFlowsAndGroups()
959 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400960 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400961 } else {
962 if outPortNo == 0 {
963 log.Warnw("outPort-should-be-specified", log.Fields{"outPortNo": outPortNo})
964 }
965 var fa *fu.FlowArgs
966 fa = &fu.FlowArgs{
967 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
968 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400969 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400970 },
971 }
972 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400973 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
974
975 //Augment the actions
976 filteredAction := GetActions(flow, OUTPUT)
977 filteredAction = append(filteredAction, Output(egressHop.Egress))
978 fa.Actions = filteredAction
979
khenaidoo89b0e942018-10-21 21:11:33 -0400980 fg := fu.NewFlowsAndGroups()
981 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400982 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400983 }
984 }
985 return deviceRules
986}
987
khenaidood20a5852018-10-22 22:09:55 -0400988// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
989func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
990 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
991
khenaidoo89b0e942018-10-21 21:11:33 -0400992 log.Debugw("downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400993 deviceRules := fu.NewDeviceRules()
994
khenaidoo89b0e942018-10-21 21:11:33 -0400995 if outPortNo != 0 {
996 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
997 }
998 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400999 egressHop := route[1]
1000
khenaidoo89b0e942018-10-21 21:11:33 -04001001 if GetMetaData(flow) != 0 {
1002 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
1003 portNumber := uint32(GetPortNumberFromMetadata(flow))
1004 if portNumber != 0 {
khenaidoo19d7b632018-10-30 10:49:50 -04001005 recalculatedRoute := agent.GetRoute(inPortNo, portNumber)
khenaidoo89b0e942018-10-21 21:11:33 -04001006 switch len(recalculatedRoute) {
1007 case 0:
1008 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": GetMetaData64Bit(flow)})
1009 // TODO: Delete flow
1010 return deviceRules
1011 case 2:
khenaidood20a5852018-10-22 22:09:55 -04001012 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -04001013 break
1014 default:
1015 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
1016 return deviceRules
1017 }
1018 ingressHop = recalculatedRoute[0]
1019 }
1020 innerTag := GetInnerTagFromMetaData(flow)
1021 if innerTag == 0 {
1022 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": GetMetaData64Bit(flow)})
1023 // TODO: Delete flow
1024 return deviceRules
1025 }
1026 var fa *fu.FlowArgs
1027 fa = &fu.FlowArgs{
1028 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1029 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001030 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001031 Metadata_ofp(innerTag),
1032 },
1033 Actions: GetActions(flow),
1034 }
1035 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001036 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT, METADATA)...)
1037
1038 // Augment the Actions
khenaidoo89b0e942018-10-21 21:11:33 -04001039 fa.Actions = append(fa.Actions, Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -04001040
khenaidoo89b0e942018-10-21 21:11:33 -04001041 fg := fu.NewFlowsAndGroups()
1042 fg.AddFlow(MkFlowStat(fa))
1043 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
1044 } else { // Create standard flow
1045 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
1046 var fa *fu.FlowArgs
1047 fa = &fu.FlowArgs{
1048 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1049 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001050 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001051 },
1052 Actions: GetActions(flow),
1053 }
1054 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001055 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1056
1057 // Augment the Actions
khenaidoo89b0e942018-10-21 21:11:33 -04001058 fa.Actions = append(fa.Actions, Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -04001059
khenaidoo89b0e942018-10-21 21:11:33 -04001060 fg := fu.NewFlowsAndGroups()
1061 fg.AddFlow(MkFlowStat(fa))
1062 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
1063 }
1064 return deviceRules
1065}
1066
khenaidood20a5852018-10-22 22:09:55 -04001067// processUnicastFlow decomposes unicast flows
1068func (fd *FlowDecomposer) processUnicastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
1069 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
1070
khenaidoo89b0e942018-10-21 21:11:33 -04001071 log.Debugw("unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -04001072 deviceRules := fu.NewDeviceRules()
1073
1074 ingressHop := route[0]
1075 egressHop := route[1]
1076
khenaidoo89b0e942018-10-21 21:11:33 -04001077 var actions []ofp.OfpActionType
1078 var isOutputTypeInActions bool
1079 for _, action := range GetActions(flow) {
1080 actions = append(actions, action.Type)
1081 if !isOutputTypeInActions && action.Type == OUTPUT {
1082 isOutputTypeInActions = true
1083 }
1084 }
1085 if len(actions) == 1 && isOutputTypeInActions {
1086 var fa *fu.FlowArgs
1087 // Parent device flow
1088 fa = &fu.FlowArgs{
1089 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1090 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001091 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001092 },
1093 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -04001094 Output(ingressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -04001095 },
1096 }
1097 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001098 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1099
khenaidoo89b0e942018-10-21 21:11:33 -04001100 fg := fu.NewFlowsAndGroups()
1101 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001102 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001103
1104 // Child device flow
1105 fa = &fu.FlowArgs{
1106 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1107 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001108 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001109 },
1110 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -04001111 Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -04001112 },
1113 }
1114 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001115 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1116
khenaidoo89b0e942018-10-21 21:11:33 -04001117 fg = fu.NewFlowsAndGroups()
1118 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001119 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001120 } else {
1121 var fa *fu.FlowArgs
1122 fa = &fu.FlowArgs{
1123 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1124 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001125 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001126 },
1127 }
1128 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001129 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1130
khenaidoo89b0e942018-10-21 21:11:33 -04001131 // Augment the Actions
khenaidood20a5852018-10-22 22:09:55 -04001132 filteredAction := GetActions(flow, OUTPUT)
1133 filteredAction = append(filteredAction, Output(egressHop.Egress))
1134 fa.Actions = filteredAction
1135
khenaidoo89b0e942018-10-21 21:11:33 -04001136 fg := fu.NewFlowsAndGroups()
1137 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001138 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001139 }
1140 return deviceRules
1141}
1142
khenaidood20a5852018-10-22 22:09:55 -04001143// processMulticastFlow decompose multicast flows
1144func (fd *FlowDecomposer) processMulticastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
1145 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpId uint32,
1146 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
1147
khenaidoo89b0e942018-10-21 21:11:33 -04001148 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -04001149 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -04001150
1151 //having no Group yet is the same as having a Group with no buckets
1152 var grp *ofp.OfpGroupEntry
1153 var ok bool
1154 if grp, ok = groupMap[grpId]; !ok {
1155 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpId, "groupMap": groupMap})
1156 return deviceRules
1157 }
1158 if grp == nil || grp.Desc == nil {
1159 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpId, "grp": grp})
1160 return deviceRules
1161 }
1162 for _, bucket := range grp.Desc.Buckets {
1163 otherActions := make([]*ofp.OfpAction, 0)
1164 for _, action := range bucket.Actions {
1165 if action.Type == OUTPUT {
1166 outPortNo = action.GetOutput().Port
1167 } else if action.Type != POP_VLAN {
1168 otherActions = append(otherActions, action)
1169 }
1170 }
1171
khenaidoo19d7b632018-10-30 10:49:50 -04001172 route2 := agent.GetRoute(inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001173 switch len(route2) {
1174 case 0:
1175 log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"})
1176 // TODO: Delete flow
1177 return deviceRules
1178 case 2:
khenaidood20a5852018-10-22 22:09:55 -04001179 log.Debugw("route-found", log.Fields{"ingressHop": route2[0], "egressHop": route2[1]})
khenaidoo89b0e942018-10-21 21:11:33 -04001180 break
1181 default:
1182 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
1183 return deviceRules
1184 }
1185
khenaidood20a5852018-10-22 22:09:55 -04001186 ingressHop := route[0]
1187 ingressHop2 := route2[0]
1188 egressHop := route2[1]
1189
1190 if ingressHop.Ingress != ingressHop2.Ingress {
khenaidoo89b0e942018-10-21 21:11:33 -04001191 log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"})
1192 return deviceRules
1193 }
1194 // Set the parent device flow
1195 var fa *fu.FlowArgs
1196 fa = &fu.FlowArgs{
1197 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1198 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001199 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001200 },
1201 }
1202 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001203 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1204
khenaidoo89b0e942018-10-21 21:11:33 -04001205 // Augment the Actions
khenaidood20a5852018-10-22 22:09:55 -04001206 filteredAction := GetActions(flow, GROUP)
1207 filteredAction = append(filteredAction, PopVlan())
1208 filteredAction = append(filteredAction, Output(route2[1].Ingress))
1209 fa.Actions = filteredAction
1210
khenaidoo89b0e942018-10-21 21:11:33 -04001211 fg := fu.NewFlowsAndGroups()
1212 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001213 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001214
1215 // Set the child device flow
1216 fa = &fu.FlowArgs{
1217 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1218 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001219 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001220 },
1221 }
1222 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001223 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT, VLAN_VID, VLAN_PCP)...)
1224
khenaidoo89b0e942018-10-21 21:11:33 -04001225 // Augment the Actions
khenaidood20a5852018-10-22 22:09:55 -04001226 otherActions = append(otherActions, Output(egressHop.Egress))
khenaidoo89b0e942018-10-21 21:11:33 -04001227 fa.Actions = otherActions
khenaidood20a5852018-10-22 22:09:55 -04001228
khenaidoo89b0e942018-10-21 21:11:33 -04001229 fg = fu.NewFlowsAndGroups()
1230 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001231 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001232 }
1233 return deviceRules
1234}
1235
khenaidood20a5852018-10-22 22:09:55 -04001236// decomposeFlow decomposes a flow for a logical device into flows for each physical device
1237func (fd *FlowDecomposer) decomposeFlow(agent coreIf.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
1238 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
1239
khenaidoo89b0e942018-10-21 21:11:33 -04001240 inPortNo := GetInPort(flow)
1241 outPortNo := GetOutPort(flow)
1242
1243 deviceRules := fu.NewDeviceRules()
1244
khenaidoo19d7b632018-10-30 10:49:50 -04001245 route := agent.GetRoute(inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001246 switch len(route) {
1247 case 0:
1248 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"})
1249 // TODO: Delete flow
1250 return deviceRules
1251 case 2:
1252 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
1253 break
1254 default:
1255 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
1256 return deviceRules
1257 }
1258
khenaidoo89b0e942018-10-21 21:11:33 -04001259 // Process controller bound flow
1260 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
khenaidood20a5852018-10-22 22:09:55 -04001261 deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001262 } else {
khenaidoo297cd252019-02-07 22:10:23 -05001263 var ingressDevice *voltha.Device
1264 var err error
1265 if ingressDevice, err = fd.deviceMgr.GetDevice(route[0].DeviceID); err != nil {
1266 log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID, "flow": flow})
1267 return deviceRules
1268 }
1269 isUpstream := !ingressDevice.Root
khenaidoo89b0e942018-10-21 21:11:33 -04001270 if isUpstream {
khenaidood20a5852018-10-22 22:09:55 -04001271 deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001272 } else if HasNextTable(flow) {
khenaidood20a5852018-10-22 22:09:55 -04001273 deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001274 } else if outPortNo != 0 { // Unicast
khenaidood20a5852018-10-22 22:09:55 -04001275 deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001276 } else if grpId := GetGroup(flow); grpId != 0 { //Multicast
khenaidood20a5852018-10-22 22:09:55 -04001277 deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, grpId, groupMap)
khenaidoo89b0e942018-10-21 21:11:33 -04001278 }
1279 }
khenaidoo19d7b632018-10-30 10:49:50 -04001280 deviceRules = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
khenaidoo89b0e942018-10-21 21:11:33 -04001281 return deviceRules
1282}