blob: 284bef2168280175daac9e0aca432a843397717a [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
410func GetOutPort(flow *ofp.OfpFlowStats) uint32 {
411 if flow == nil {
412 return 0
413 }
414 for _, action := range GetActions(flow) {
415 if action.Type == OUTPUT {
416 out := action.GetOutput()
417 if out == nil {
418 return 0
419 }
420 return out.GetPort()
421 }
422 }
423 return 0
424}
425
426func GetInPort(flow *ofp.OfpFlowStats) uint32 {
427 if flow == nil {
428 return 0
429 }
430 for _, field := range GetOfbFields(flow) {
431 if field.Type == IN_PORT {
432 return field.GetPort()
433 }
434 }
435 return 0
436}
437
438func GetGotoTableId(flow *ofp.OfpFlowStats) uint32 {
439 if flow == nil {
440 return 0
441 }
442 for _, instruction := range flow.Instructions {
443 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE) {
444 gotoTable := instruction.GetGotoTable()
445 if gotoTable == nil {
446 return 0
447 }
448 return gotoTable.GetTableId()
449 }
450 }
451 return 0
452}
453
454//GetMetaData - legacy get method (only want lower 32 bits)
455func GetMetaData(flow *ofp.OfpFlowStats) uint32 {
456 if flow == nil {
457 return 0
458 }
459 for _, field := range GetOfbFields(flow) {
460 if field.Type == METADATA {
461 return uint32(field.GetTableMetadata() & 0xffffffff)
462 }
463 }
464 return 0
465}
466
467func GetMetaData64Bit(flow *ofp.OfpFlowStats) uint64 {
468 if flow == nil {
469 return 0
470 }
471 for _, field := range GetOfbFields(flow) {
472 if field.Type == METADATA {
473 return field.GetTableMetadata()
474 }
475 }
476 return 0
477}
478
479// GetPortNumberFromMetadata retrieves the port number from the Metadata_ofp. The port number (UNI on ONU) is in the
480// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
481// a Metadata_ofp field
482func GetPortNumberFromMetadata(flow *ofp.OfpFlowStats) uint64 {
483 md := GetMetaData64Bit(flow)
484 if md == 0 {
485 return 0
486 }
487 if md <= 0xffffffff {
488 log.Warnw("onos-upgrade-suggested", log.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
489 return md
490 }
491 return md & 0xffffffff
492}
493
494//GetInnerTagFromMetaData retrieves the inner tag from the Metadata_ofp. The port number (UNI on ONU) is in the
495// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
496//// a Metadata_ofp field
497func GetInnerTagFromMetaData(flow *ofp.OfpFlowStats) uint64 {
498 md := GetMetaData64Bit(flow)
499 if md == 0 {
500 return 0
501 }
502 if md <= 0xffffffff {
503 log.Warnw("onos-upgrade-suggested", log.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
504 return md
505 }
506 return (md >> 32) & 0xffffffff
507}
508
509func HasNextTable(flow *ofp.OfpFlowStats) bool {
510 if flow == nil {
511 return false
512 }
513 return GetGotoTableId(flow) != 0
514}
515
516func GetGroup(flow *ofp.OfpFlowStats) uint32 {
517 if flow == nil {
518 return 0
519 }
520 for _, action := range GetActions(flow) {
521 if action.Type == GROUP {
522 grp := action.GetGroup()
523 if grp == nil {
524 return 0
525 }
526 return grp.GetGroupId()
527 }
528 }
529 return 0
530}
531
532func HasGroup(flow *ofp.OfpFlowStats) bool {
533 return GetGroup(flow) != 0
534}
535
536// GetNextTableId returns the next table ID if the "table_id" is present in the map, otherwise return nil
537func GetNextTableId(kw fu.OfpFlowModArgs) *uint32 {
538 if val, exist := kw["table_id"]; exist {
539 ret := uint32(val)
540 return &ret
541 }
542 return nil
543}
544
545// Return unique 64-bit integer hash for flow covering the following attributes:
546// 'table_id', 'priority', 'flags', 'cookie', 'match', '_instruction_string'
547func hashFlowStats(flow *ofp.OfpFlowStats) uint64 {
548 if flow == nil { // Should never happen
549 return 0
550 }
551 // Create string with the instructions field first
552 var instructionString bytes.Buffer
553 for _, instruction := range flow.Instructions {
554 instructionString.WriteString(instruction.String())
555 }
556 var flowString = fmt.Sprintf("%d%d%d%d%s%s", flow.TableId, flow.Priority, flow.Flags, flow.Cookie, flow.Match.String(), instructionString.String())
557 h := md5.New()
558 h.Write([]byte(flowString))
559 hash := big.NewInt(0)
560 hash.SetBytes(h.Sum(nil))
561 return hash.Uint64()
562}
563
564// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
565func FlowStatsEntryFromFlowModMessage(mod *ofp.OfpFlowMod) *ofp.OfpFlowStats {
566 flow := &ofp.OfpFlowStats{}
567 if mod == nil {
568 return flow
569 }
570 flow.TableId = mod.TableId
571 flow.Priority = mod.Priority
572 flow.IdleTimeout = mod.IdleTimeout
573 flow.HardTimeout = mod.HardTimeout
574 flow.Flags = mod.Flags
575 flow.Cookie = mod.Cookie
576 flow.Match = mod.Match
577 flow.Instructions = mod.Instructions
578 flow.Id = hashFlowStats(flow)
579 return flow
580}
581
582func GroupEntryFromGroupMod(mod *ofp.OfpGroupMod) *ofp.OfpGroupEntry {
583 group := &ofp.OfpGroupEntry{}
584 if mod == nil {
585 return group
586 }
587 group.Desc = &ofp.OfpGroupDesc{Type: mod.Type, GroupId: mod.GroupId, Buckets: mod.Buckets}
588 group.Stats = &ofp.OfpGroupStats{GroupId: mod.GroupId}
khenaidood20a5852018-10-22 22:09:55 -0400589 //TODO do we need to instantiate bucket bins?
khenaidoo89b0e942018-10-21 21:11:33 -0400590 return group
591}
592
593func MkOxmFields(matchFields []ofp.OfpOxmField) []*ofp.OfpOxmField {
594 oxmFields := make([]*ofp.OfpOxmField, 0)
595 for _, matchField := range matchFields {
596 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
597 oxmFields = append(oxmFields, &oxmField)
598 }
599 return oxmFields
600}
601
602func MkInstructionsFromActions(actions []*ofp.OfpAction) []*ofp.OfpInstruction {
603 instructions := make([]*ofp.OfpInstruction, 0)
604 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
605 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
606 instructions = append(instructions, &instruction)
607 return instructions
608}
609
610// Convenience function to generare ofp_flow_mod message with OXM BASIC match composed from the match_fields, and
611// single APPLY_ACTIONS instruction with a list if ofp_action objects.
612func MkSimpleFlowMod(matchFields []*ofp.OfpOxmField, actions []*ofp.OfpAction, command *ofp.OfpFlowModCommand, kw fu.OfpFlowModArgs) *ofp.OfpFlowMod {
613
614 // Process actions instructions
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
620 // Process next table
621 if tableId := GetNextTableId(kw); tableId != nil {
622 var instGotoTable ofp.OfpInstruction_GotoTable
623 instGotoTable.GotoTable = &ofp.OfpInstructionGotoTable{TableId: *tableId}
624 inst := ofp.OfpInstruction{Type: uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE), Data: &instGotoTable}
625 instructions = append(instructions, &inst)
626 }
627
628 // Process match fields
629 oxmFields := make([]*ofp.OfpOxmField, 0)
630 for _, matchField := range matchFields {
631 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
632 oxmFields = append(oxmFields, &oxmField)
633 }
634 var match ofp.OfpMatch
635 match.Type = ofp.OfpMatchType_OFPMT_OXM
636 match.OxmFields = oxmFields
637
638 // Create ofp_flow_message
639 msg := &ofp.OfpFlowMod{}
640 if command == nil {
641 msg.Command = ofp.OfpFlowModCommand_OFPFC_ADD
642 } else {
643 msg.Command = *command
644 }
645 msg.Instructions = instructions
646 msg.Match = &match
647
648 // Set the variadic argument values
649 msg = setVariadicModAttributes(msg, kw)
650
651 return msg
652}
653
654func MkMulticastGroupMod(groupId uint32, buckets []*ofp.OfpBucket, command *ofp.OfpGroupModCommand) *ofp.OfpGroupMod {
655 group := &ofp.OfpGroupMod{}
656 if command == nil {
657 group.Command = ofp.OfpGroupModCommand_OFPGC_ADD
658 } else {
659 group.Command = *command
660 }
661 group.Type = ofp.OfpGroupType_OFPGT_ALL
662 group.GroupId = groupId
663 group.Buckets = buckets
664 return group
665}
666
667//SetVariadicModAttributes sets only uint64 or uint32 fields of the ofp_flow_mod message
668func setVariadicModAttributes(mod *ofp.OfpFlowMod, args fu.OfpFlowModArgs) *ofp.OfpFlowMod {
669 if args == nil {
670 return mod
671 }
672 for key, val := range args {
673 switch key {
674 case "cookie":
675 mod.Cookie = val
676 case "cookie_mask":
677 mod.CookieMask = val
678 case "table_id":
679 mod.TableId = uint32(val)
680 case "idle_timeout":
681 mod.IdleTimeout = uint32(val)
682 case "hard_timeout":
683 mod.HardTimeout = uint32(val)
684 case "priority":
685 mod.Priority = uint32(val)
686 case "buffer_id":
687 mod.BufferId = uint32(val)
688 case "out_port":
689 mod.OutPort = uint32(val)
690 case "out_group":
691 mod.OutGroup = uint32(val)
692 case "flags":
693 mod.Flags = uint32(val)
694 }
695 }
696 return mod
697}
698
699// MkFlowStat is a helper method to build flows
700func MkFlowStat(fa *fu.FlowArgs) *ofp.OfpFlowStats {
701 //Build the matchfields
702 matchFields := make([]*ofp.OfpOxmField, 0)
703 for _, val := range fa.MatchFields {
704 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
705 }
706 return FlowStatsEntryFromFlowModMessage(MkSimpleFlowMod(matchFields, fa.Actions, fa.Command, fa.KV))
707}
708
khenaidood20a5852018-10-22 22:09:55 -0400709func MkGroupStat(ga *fu.GroupArgs) *ofp.OfpGroupEntry {
710 return GroupEntryFromGroupMod(MkMulticastGroupMod(ga.GroupId, ga.Buckets, ga.Command))
khenaidoo89b0e942018-10-21 21:11:33 -0400711}
712
713type FlowDecomposer struct {
714 deviceMgr coreIf.DeviceManager
715}
716
717func NewFlowDecomposer(deviceMgr coreIf.DeviceManager) *FlowDecomposer {
718 var decomposer FlowDecomposer
719 decomposer.deviceMgr = deviceMgr
720 return &decomposer
721}
722
723//DecomposeRules decomposes per-device flows and flow-groups from the flows and groups defined on a logical device
724func (fd *FlowDecomposer) DecomposeRules(agent coreIf.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups) *fu.DeviceRules {
725 rules := agent.GetAllDefaultRules()
726 deviceRules := rules.Copy()
727
728 groupMap := make(map[uint32]*ofp.OfpGroupEntry)
729 for _, groupEntry := range groups.Items {
730 groupMap[groupEntry.Desc.GroupId] = groupEntry
731 }
732
733 var decomposedRules *fu.DeviceRules
734 for _, flow := range flows.Items {
735 decomposedRules = fd.decomposeFlow(agent, flow, groupMap)
736 for deviceId, flowAndGroups := range decomposedRules.Rules {
khenaidood20a5852018-10-22 22:09:55 -0400737 deviceRules.CreateEntryIfNotExist(deviceId)
khenaidoo89b0e942018-10-21 21:11:33 -0400738 deviceRules.Rules[deviceId].AddFrom(flowAndGroups)
739 }
740 }
741 return deviceRules
742}
743
khenaidoo19d7b632018-10-30 10:49:50 -0400744// Handles special case of any controller-bound flow for a parent device
745func (fd *FlowDecomposer) updateOutputPortForControllerBoundFlowForParentDevide(flow *ofp.OfpFlowStats,
746 dr *fu.DeviceRules) *fu.DeviceRules {
747 EAPOL := EthType(0x888e)
748 IGMP := IpProto(2)
749 UDP := IpProto(17)
750
751 newDeviceRules := dr.Copy()
752 // Check whether we are dealing with a parent device
753 for deviceId, fg := range dr.GetRules() {
754 if root, _ := fd.deviceMgr.IsRootDevice(deviceId); root {
755 newDeviceRules.ClearFlows(deviceId)
756 for i := 0; i < fg.Flows.Len(); i++ {
757 f := fg.GetFlow(i)
758 UpdateOutPortNo := false
759 for _, field := range GetOfbFields(f) {
760 UpdateOutPortNo = (field.String() == EAPOL.String())
761 UpdateOutPortNo = UpdateOutPortNo || (field.String() == IGMP.String())
762 UpdateOutPortNo = UpdateOutPortNo || (field.String() == UDP.String())
763 if UpdateOutPortNo {
764 break
765 }
766 }
767 if UpdateOutPortNo {
768 f = UpdateOutputPortByActionType(f, uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS),
769 uint32(ofp.OfpPortNo_OFPP_CONTROLLER))
770 }
771 // Update flow Id as a change in the instruction field will result in a new flow ID
772 f.Id = hashFlowStats(f)
773 newDeviceRules.AddFlow(deviceId, (proto.Clone(f)).(*ofp.OfpFlowStats))
774 }
775 }
776 }
777 return newDeviceRules
778}
779
khenaidood20a5852018-10-22 22:09:55 -0400780//processControllerBoundFlow decomposes trap flows
781func (fd *FlowDecomposer) processControllerBoundFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
782 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
783
khenaidoo89b0e942018-10-21 21:11:33 -0400784 log.Debugw("trap-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "flow": flow})
khenaidood20a5852018-10-22 22:09:55 -0400785 deviceRules := fu.NewDeviceRules()
786
787 egressHop := route[1]
788
khenaidoo89b0e942018-10-21 21:11:33 -0400789 fg := fu.NewFlowsAndGroups()
790 if agent.GetDeviceGraph().IsRootPort(inPortNo) {
791 log.Debug("trap-nni")
792 var fa *fu.FlowArgs
793 fa = &fu.FlowArgs{
794 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
795 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400796 InPort(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400797 },
798 Actions: GetActions(flow),
799 }
800 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400801 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400802 fg.AddFlow(MkFlowStat(fa))
803 } else {
804 // Trap flow for UNI port
805 log.Debug("trap-uni")
806
807 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
808 var inPorts []uint32
809 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400810 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400811 } else {
812 inPorts = []uint32{inPortNo}
813 }
814 for _, inputPort := range inPorts {
815 var fa *fu.FlowArgs
816 // Upstream flow
817 fa = &fu.FlowArgs{
818 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
819 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400820 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400821 VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | inputPort),
822 },
823 Actions: []*ofp.OfpAction{
824 PushVlan(0x8100),
825 SetField(VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
khenaidood20a5852018-10-22 22:09:55 -0400826 Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400827 },
828 }
829 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400830 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT, VLAN_VID)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400831 fg.AddFlow(MkFlowStat(fa))
832
833 // Downstream flow
834 fa = &fu.FlowArgs{
835 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority)},
836 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400837 InPort(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400838 VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000),
839 VlanPcp(0),
840 Metadata_ofp(uint64(inputPort)),
841 },
842 Actions: []*ofp.OfpAction{
843 PopVlan(),
khenaidood20a5852018-10-22 22:09:55 -0400844 Output(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400845 },
846 }
847 fg.AddFlow(MkFlowStat(fa))
848 }
849 }
khenaidood20a5852018-10-22 22:09:55 -0400850 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400851 return deviceRules
852}
853
854// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
855// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
856// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
857// applied at the OLT
khenaidood20a5852018-10-22 22:09:55 -0400858func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreIf.LogicalDeviceAgent,
859 route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
860
khenaidoo89b0e942018-10-21 21:11:33 -0400861 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400862 deviceRules := fu.NewDeviceRules()
863
864 ingressHop := route[0]
865 egressHop := route[1]
866
khenaidoo89b0e942018-10-21 21:11:33 -0400867 if HasNextTable(flow) {
868 log.Debugw("has-next-table", log.Fields{"table_id": flow.TableId})
869 if outPortNo != 0 {
870 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
871 }
872 var fa *fu.FlowArgs
873 fa = &fu.FlowArgs{
874 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
875 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400876 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400877 },
878 Actions: GetActions(flow),
879 }
880 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400881 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
882
883 // Augment the Actions
884 fa.Actions = append(fa.Actions, Output(ingressHop.Egress))
885
khenaidoo89b0e942018-10-21 21:11:33 -0400886 fg := fu.NewFlowsAndGroups()
887 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400888 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400889 } else {
890 var actions []ofp.OfpActionType
891 var isOutputTypeInActions bool
892 for _, action := range GetActions(flow) {
893 actions = append(actions, action.Type)
894 if !isOutputTypeInActions && action.Type == OUTPUT {
895 isOutputTypeInActions = true
896 }
897 }
898 if len(actions) == 1 && isOutputTypeInActions {
899 var fa *fu.FlowArgs
900 // child device flow
901 fa = &fu.FlowArgs{
902 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
903 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400904 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400905 },
906 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -0400907 Output(ingressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400908 },
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)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400912 fg := fu.NewFlowsAndGroups()
913 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400914 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400915
916 // parent device flow
917 fa = &fu.FlowArgs{
918 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
919 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400920 InPort(egressHop.Ingress), //egress_hop.ingress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400921 },
922 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -0400923 Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400924 },
925 }
926 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400927 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400928 fg = fu.NewFlowsAndGroups()
929 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400930 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400931 } else {
932 if outPortNo == 0 {
933 log.Warnw("outPort-should-be-specified", log.Fields{"outPortNo": outPortNo})
934 }
935 var fa *fu.FlowArgs
936 fa = &fu.FlowArgs{
937 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
938 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400939 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400940 },
941 }
942 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400943 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
944
945 //Augment the actions
946 filteredAction := GetActions(flow, OUTPUT)
947 filteredAction = append(filteredAction, Output(egressHop.Egress))
948 fa.Actions = filteredAction
949
khenaidoo89b0e942018-10-21 21:11:33 -0400950 fg := fu.NewFlowsAndGroups()
951 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400952 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400953 }
954 }
955 return deviceRules
956}
957
khenaidood20a5852018-10-22 22:09:55 -0400958// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
959func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
960 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
961
khenaidoo89b0e942018-10-21 21:11:33 -0400962 log.Debugw("downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400963 deviceRules := fu.NewDeviceRules()
964
khenaidoo89b0e942018-10-21 21:11:33 -0400965 if outPortNo != 0 {
966 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
967 }
968 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400969 egressHop := route[1]
970
khenaidoo89b0e942018-10-21 21:11:33 -0400971 if GetMetaData(flow) != 0 {
972 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
973 portNumber := uint32(GetPortNumberFromMetadata(flow))
974 if portNumber != 0 {
khenaidoo19d7b632018-10-30 10:49:50 -0400975 recalculatedRoute := agent.GetRoute(inPortNo, portNumber)
khenaidoo89b0e942018-10-21 21:11:33 -0400976 switch len(recalculatedRoute) {
977 case 0:
978 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": GetMetaData64Bit(flow)})
979 // TODO: Delete flow
980 return deviceRules
981 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400982 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400983 break
984 default:
985 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
986 return deviceRules
987 }
988 ingressHop = recalculatedRoute[0]
989 }
990 innerTag := GetInnerTagFromMetaData(flow)
991 if innerTag == 0 {
992 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": GetMetaData64Bit(flow)})
993 // TODO: Delete flow
994 return deviceRules
995 }
996 var fa *fu.FlowArgs
997 fa = &fu.FlowArgs{
998 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
999 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001000 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001001 Metadata_ofp(innerTag),
1002 },
1003 Actions: GetActions(flow),
1004 }
1005 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001006 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT, METADATA)...)
1007
1008 // Augment the Actions
khenaidoo89b0e942018-10-21 21:11:33 -04001009 fa.Actions = append(fa.Actions, Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -04001010
khenaidoo89b0e942018-10-21 21:11:33 -04001011 fg := fu.NewFlowsAndGroups()
1012 fg.AddFlow(MkFlowStat(fa))
1013 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
1014 } else { // Create standard flow
1015 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
1016 var fa *fu.FlowArgs
1017 fa = &fu.FlowArgs{
1018 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1019 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001020 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001021 },
1022 Actions: GetActions(flow),
1023 }
1024 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001025 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1026
1027 // Augment the Actions
khenaidoo89b0e942018-10-21 21:11:33 -04001028 fa.Actions = append(fa.Actions, Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -04001029
khenaidoo89b0e942018-10-21 21:11:33 -04001030 fg := fu.NewFlowsAndGroups()
1031 fg.AddFlow(MkFlowStat(fa))
1032 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
1033 }
1034 return deviceRules
1035}
1036
khenaidood20a5852018-10-22 22:09:55 -04001037// processUnicastFlow decomposes unicast flows
1038func (fd *FlowDecomposer) processUnicastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
1039 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
1040
khenaidoo89b0e942018-10-21 21:11:33 -04001041 log.Debugw("unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -04001042 deviceRules := fu.NewDeviceRules()
1043
1044 ingressHop := route[0]
1045 egressHop := route[1]
1046
khenaidoo89b0e942018-10-21 21:11:33 -04001047 var actions []ofp.OfpActionType
1048 var isOutputTypeInActions bool
1049 for _, action := range GetActions(flow) {
1050 actions = append(actions, action.Type)
1051 if !isOutputTypeInActions && action.Type == OUTPUT {
1052 isOutputTypeInActions = true
1053 }
1054 }
1055 if len(actions) == 1 && isOutputTypeInActions {
1056 var fa *fu.FlowArgs
1057 // Parent device flow
1058 fa = &fu.FlowArgs{
1059 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1060 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001061 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001062 },
1063 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -04001064 Output(ingressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -04001065 },
1066 }
1067 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001068 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1069
khenaidoo89b0e942018-10-21 21:11:33 -04001070 fg := fu.NewFlowsAndGroups()
1071 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001072 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001073
1074 // Child device flow
1075 fa = &fu.FlowArgs{
1076 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1077 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001078 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001079 },
1080 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -04001081 Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -04001082 },
1083 }
1084 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001085 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1086
khenaidoo89b0e942018-10-21 21:11:33 -04001087 fg = fu.NewFlowsAndGroups()
1088 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001089 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001090 } else {
1091 var fa *fu.FlowArgs
1092 fa = &fu.FlowArgs{
1093 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1094 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001095 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001096 },
1097 }
1098 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001099 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1100
khenaidoo89b0e942018-10-21 21:11:33 -04001101 // Augment the Actions
khenaidood20a5852018-10-22 22:09:55 -04001102 filteredAction := GetActions(flow, OUTPUT)
1103 filteredAction = append(filteredAction, Output(egressHop.Egress))
1104 fa.Actions = filteredAction
1105
khenaidoo89b0e942018-10-21 21:11:33 -04001106 fg := fu.NewFlowsAndGroups()
1107 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001108 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001109 }
1110 return deviceRules
1111}
1112
khenaidood20a5852018-10-22 22:09:55 -04001113// processMulticastFlow decompose multicast flows
1114func (fd *FlowDecomposer) processMulticastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
1115 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpId uint32,
1116 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
1117
khenaidoo89b0e942018-10-21 21:11:33 -04001118 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -04001119 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -04001120
1121 //having no Group yet is the same as having a Group with no buckets
1122 var grp *ofp.OfpGroupEntry
1123 var ok bool
1124 if grp, ok = groupMap[grpId]; !ok {
1125 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpId, "groupMap": groupMap})
1126 return deviceRules
1127 }
1128 if grp == nil || grp.Desc == nil {
1129 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpId, "grp": grp})
1130 return deviceRules
1131 }
1132 for _, bucket := range grp.Desc.Buckets {
1133 otherActions := make([]*ofp.OfpAction, 0)
1134 for _, action := range bucket.Actions {
1135 if action.Type == OUTPUT {
1136 outPortNo = action.GetOutput().Port
1137 } else if action.Type != POP_VLAN {
1138 otherActions = append(otherActions, action)
1139 }
1140 }
1141
khenaidoo19d7b632018-10-30 10:49:50 -04001142 route2 := agent.GetRoute(inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001143 switch len(route2) {
1144 case 0:
1145 log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"})
1146 // TODO: Delete flow
1147 return deviceRules
1148 case 2:
khenaidood20a5852018-10-22 22:09:55 -04001149 log.Debugw("route-found", log.Fields{"ingressHop": route2[0], "egressHop": route2[1]})
khenaidoo89b0e942018-10-21 21:11:33 -04001150 break
1151 default:
1152 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
1153 return deviceRules
1154 }
1155
khenaidood20a5852018-10-22 22:09:55 -04001156 ingressHop := route[0]
1157 ingressHop2 := route2[0]
1158 egressHop := route2[1]
1159
1160 if ingressHop.Ingress != ingressHop2.Ingress {
khenaidoo89b0e942018-10-21 21:11:33 -04001161 log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"})
1162 return deviceRules
1163 }
1164 // Set the parent device flow
1165 var fa *fu.FlowArgs
1166 fa = &fu.FlowArgs{
1167 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1168 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001169 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001170 },
1171 }
1172 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001173 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1174
khenaidoo89b0e942018-10-21 21:11:33 -04001175 // Augment the Actions
khenaidood20a5852018-10-22 22:09:55 -04001176 filteredAction := GetActions(flow, GROUP)
1177 filteredAction = append(filteredAction, PopVlan())
1178 filteredAction = append(filteredAction, Output(route2[1].Ingress))
1179 fa.Actions = filteredAction
1180
khenaidoo89b0e942018-10-21 21:11:33 -04001181 fg := fu.NewFlowsAndGroups()
1182 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001183 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001184
1185 // Set the child device flow
1186 fa = &fu.FlowArgs{
1187 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1188 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001189 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001190 },
1191 }
1192 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001193 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT, VLAN_VID, VLAN_PCP)...)
1194
khenaidoo89b0e942018-10-21 21:11:33 -04001195 // Augment the Actions
khenaidood20a5852018-10-22 22:09:55 -04001196 otherActions = append(otherActions, Output(egressHop.Egress))
khenaidoo89b0e942018-10-21 21:11:33 -04001197 fa.Actions = otherActions
khenaidood20a5852018-10-22 22:09:55 -04001198
khenaidoo89b0e942018-10-21 21:11:33 -04001199 fg = fu.NewFlowsAndGroups()
1200 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001201 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001202 }
1203 return deviceRules
1204}
1205
khenaidood20a5852018-10-22 22:09:55 -04001206// decomposeFlow decomposes a flow for a logical device into flows for each physical device
1207func (fd *FlowDecomposer) decomposeFlow(agent coreIf.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
1208 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
1209
khenaidoo89b0e942018-10-21 21:11:33 -04001210 inPortNo := GetInPort(flow)
1211 outPortNo := GetOutPort(flow)
1212
1213 deviceRules := fu.NewDeviceRules()
1214
khenaidoo19d7b632018-10-30 10:49:50 -04001215 route := agent.GetRoute(inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001216 switch len(route) {
1217 case 0:
1218 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"})
1219 // TODO: Delete flow
1220 return deviceRules
1221 case 2:
1222 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
1223 break
1224 default:
1225 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
1226 return deviceRules
1227 }
1228
1229 var ingressDevice *voltha.Device
khenaidoo89b0e942018-10-21 21:11:33 -04001230 var err error
1231 if ingressDevice, err = fd.deviceMgr.GetDevice(route[0].DeviceID); err != nil {
1232 log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID})
1233 return deviceRules
1234 }
khenaidoo89b0e942018-10-21 21:11:33 -04001235
1236 isDownstream := ingressDevice.Root
1237 isUpstream := !isDownstream
1238
1239 // Process controller bound flow
1240 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
khenaidood20a5852018-10-22 22:09:55 -04001241 deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001242 } else {
1243 if isUpstream {
khenaidood20a5852018-10-22 22:09:55 -04001244 deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001245 } else if HasNextTable(flow) {
khenaidood20a5852018-10-22 22:09:55 -04001246 deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001247 } else if outPortNo != 0 { // Unicast
khenaidood20a5852018-10-22 22:09:55 -04001248 deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001249 } else if grpId := GetGroup(flow); grpId != 0 { //Multicast
khenaidood20a5852018-10-22 22:09:55 -04001250 deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, grpId, groupMap)
khenaidoo89b0e942018-10-21 21:11:33 -04001251 }
1252 }
khenaidoo19d7b632018-10-30 10:49:50 -04001253 deviceRules = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
khenaidoo89b0e942018-10-21 21:11:33 -04001254 return deviceRules
1255}