blob: 54a67614546ab490a91b6d870a3c99008f07149e [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"
23 "github.com/opencord/voltha-go/common/log"
24 ofp "github.com/opencord/voltha-go/protos/openflow_13"
25 "github.com/opencord/voltha-go/protos/voltha"
26 "github.com/opencord/voltha-go/rw_core/coreIf"
27 "github.com/opencord/voltha-go/rw_core/graph"
28 fu "github.com/opencord/voltha-go/rw_core/utils"
29 "math/big"
30)
31
32func init() {
33 log.AddPackage(log.JSON, log.DebugLevel, nil)
34}
35
36var (
37 // Instructions shortcut
38 APPLY_ACTIONS = ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS
39
40 //OFPAT_* shortcuts
41 OUTPUT = ofp.OfpActionType_OFPAT_OUTPUT
42 COPY_TTL_OUT = ofp.OfpActionType_OFPAT_COPY_TTL_OUT
43 COPY_TTL_IN = ofp.OfpActionType_OFPAT_COPY_TTL_IN
44 SET_MPLS_TTL = ofp.OfpActionType_OFPAT_SET_MPLS_TTL
45 DEC_MPLS_TTL = ofp.OfpActionType_OFPAT_DEC_MPLS_TTL
46 PUSH_VLAN = ofp.OfpActionType_OFPAT_PUSH_VLAN
47 POP_VLAN = ofp.OfpActionType_OFPAT_POP_VLAN
48 PUSH_MPLS = ofp.OfpActionType_OFPAT_PUSH_MPLS
49 POP_MPLS = ofp.OfpActionType_OFPAT_POP_MPLS
50 SET_QUEUE = ofp.OfpActionType_OFPAT_SET_QUEUE
51 GROUP = ofp.OfpActionType_OFPAT_GROUP
52 SET_NW_TTL = ofp.OfpActionType_OFPAT_SET_NW_TTL
53 NW_TTL = ofp.OfpActionType_OFPAT_DEC_NW_TTL
54 SET_FIELD = ofp.OfpActionType_OFPAT_SET_FIELD
55 PUSH_PBB = ofp.OfpActionType_OFPAT_PUSH_PBB
56 POP_PBB = ofp.OfpActionType_OFPAT_POP_PBB
57 EXPERIMENTER = ofp.OfpActionType_OFPAT_EXPERIMENTER
58
59 //OFPXMT_OFB_* shortcuts (incomplete)
60 IN_PORT = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT
61 IN_PHY_PORT = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT
62 METADATA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_METADATA
63 ETH_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_DST
64 ETH_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_SRC
65 ETH_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE
66 VLAN_VID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID
67 VLAN_PCP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP
68 IP_DSCP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_DSCP
69 IP_ECN = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_ECN
70 IP_PROTO = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO
71 IPV4_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_SRC
72 IPV4_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST
73 TCP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TCP_SRC
74 TCP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TCP_DST
75 UDP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC
76 UDP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST
77 SCTP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_SCTP_SRC
78 SCTP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_SCTP_DST
79 ICMPV4_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV4_TYPE
80 ICMPV4_CODE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV4_CODE
81 ARP_OP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_OP
82 ARP_SPA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_SPA
83 ARP_TPA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_TPA
84 ARP_SHA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_SHA
85 ARP_THA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_THA
86 IPV6_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_SRC
87 IPV6_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_DST
88 IPV6_FLABEL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_FLABEL
89 ICMPV6_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV6_TYPE
90 ICMPV6_CODE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV6_CODE
91 IPV6_ND_TARGET = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_TARGET
92 OFB_IPV6_ND_SLL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_SLL
93 IPV6_ND_TLL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_TLL
94 MPLS_LABEL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_LABEL
95 MPLS_TC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_TC
96 MPLS_BOS = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_BOS
97 PBB_ISID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_PBB_ISID
98 TUNNEL_ID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TUNNEL_ID
99 IPV6_EXTHDR = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_EXTHDR
100)
101
102//ofp_action_* shortcuts
103
104func Output(port uint32, maxLen ...ofp.OfpControllerMaxLen) *ofp.OfpAction {
105 maxLength := ofp.OfpControllerMaxLen_OFPCML_MAX
106 if len(maxLen) > 0 {
107 maxLength = maxLen[0]
108 }
109 return &ofp.OfpAction{Type: OUTPUT, Action: &ofp.OfpAction_Output{Output: &ofp.OfpActionOutput{Port: port, MaxLen: uint32(maxLength)}}}
110}
111
112func MplsTtl(ttl uint32) *ofp.OfpAction {
113 return &ofp.OfpAction{Type: SET_MPLS_TTL, Action: &ofp.OfpAction_MplsTtl{MplsTtl: &ofp.OfpActionMplsTtl{MplsTtl: ttl}}}
114}
115
116func PushVlan(ethType uint32) *ofp.OfpAction {
117 return &ofp.OfpAction{Type: PUSH_VLAN, Action: &ofp.OfpAction_Push{Push: &ofp.OfpActionPush{Ethertype: ethType}}}
118}
119
120func PopVlan() *ofp.OfpAction {
121 return &ofp.OfpAction{Type: POP_VLAN}
122}
123
124func PopMpls(ethType uint32) *ofp.OfpAction {
125 return &ofp.OfpAction{Type: POP_MPLS, Action: &ofp.OfpAction_PopMpls{PopMpls: &ofp.OfpActionPopMpls{Ethertype: ethType}}}
126}
127
128func Group(groupId uint32) *ofp.OfpAction {
129 return &ofp.OfpAction{Type: GROUP, Action: &ofp.OfpAction_Group{Group: &ofp.OfpActionGroup{GroupId: groupId}}}
130}
131
132func NwTtl(nwTtl uint32) *ofp.OfpAction {
133 return &ofp.OfpAction{Type: NW_TTL, Action: &ofp.OfpAction_NwTtl{NwTtl: &ofp.OfpActionNwTtl{NwTtl: nwTtl}}}
134}
135
136func SetField(field *ofp.OfpOxmOfbField) *ofp.OfpAction {
137 actionSetField := &ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: &ofp.OfpOxmField_OfbField{OfbField: field}}
138 return &ofp.OfpAction{Type: SET_FIELD, Action: &ofp.OfpAction_SetField{SetField: &ofp.OfpActionSetField{Field: actionSetField}}}
139}
140
141func Experimenter(experimenter uint32, data []byte) *ofp.OfpAction {
142 return &ofp.OfpAction{Type: EXPERIMENTER, Action: &ofp.OfpAction_Experimenter{Experimenter: &ofp.OfpActionExperimenter{Experimenter: experimenter, Data: data}}}
143}
144
145//ofb_field generators (incomplete set)
146
147func InPort(inPort uint32) *ofp.OfpOxmOfbField {
148 return &ofp.OfpOxmOfbField{Type: IN_PORT, Value: &ofp.OfpOxmOfbField_Port{Port: inPort}}
149}
150
151func InPhyPort(inPhyPort uint32) *ofp.OfpOxmOfbField {
152 return &ofp.OfpOxmOfbField{Type: IN_PHY_PORT, Value: &ofp.OfpOxmOfbField_Port{Port: inPhyPort}}
153}
154
155func Metadata_ofp(tableMetadata uint64) *ofp.OfpOxmOfbField {
156 return &ofp.OfpOxmOfbField{Type: METADATA, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: tableMetadata}}
157}
158
159// should Metadata_ofp used here ?????
160func EthDst(ethDst uint64) *ofp.OfpOxmOfbField {
161 return &ofp.OfpOxmOfbField{Type: ETH_DST, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: ethDst}}
162}
163
164// should Metadata_ofp used here ?????
165func EthSrc(ethSrc uint64) *ofp.OfpOxmOfbField {
166 return &ofp.OfpOxmOfbField{Type: ETH_SRC, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: ethSrc}}
167}
168
169func EthType(ethType uint32) *ofp.OfpOxmOfbField {
170 return &ofp.OfpOxmOfbField{Type: ETH_TYPE, Value: &ofp.OfpOxmOfbField_EthType{EthType: ethType}}
171}
172
173func VlanVid(vlanVid uint32) *ofp.OfpOxmOfbField {
174 return &ofp.OfpOxmOfbField{Type: VLAN_VID, Value: &ofp.OfpOxmOfbField_VlanVid{VlanVid: vlanVid}}
175}
176
177func VlanPcp(vlanPcp uint32) *ofp.OfpOxmOfbField {
178 return &ofp.OfpOxmOfbField{Type: VLAN_VID, Value: &ofp.OfpOxmOfbField_VlanPcp{VlanPcp: vlanPcp}}
179}
180
181func IpDscp(ipDscp uint32) *ofp.OfpOxmOfbField {
182 return &ofp.OfpOxmOfbField{Type: IP_DSCP, Value: &ofp.OfpOxmOfbField_IpDscp{IpDscp: ipDscp}}
183}
184
185func IpEcn(ipEcn uint32) *ofp.OfpOxmOfbField {
186 return &ofp.OfpOxmOfbField{Type: IP_ECN, Value: &ofp.OfpOxmOfbField_IpEcn{IpEcn: ipEcn}}
187}
188
189func IpProto(ipProto uint32) *ofp.OfpOxmOfbField {
190 return &ofp.OfpOxmOfbField{Type: IP_PROTO, Value: &ofp.OfpOxmOfbField_IpProto{IpProto: ipProto}}
191}
192
193func Ipv4Src(ipv4Src uint32) *ofp.OfpOxmOfbField {
194 return &ofp.OfpOxmOfbField{Type: IPV4_SRC, Value: &ofp.OfpOxmOfbField_Ipv4Src{Ipv4Src: ipv4Src}}
195}
196
197func Ipv4Dst(ipv4Dst uint32) *ofp.OfpOxmOfbField {
198 return &ofp.OfpOxmOfbField{Type: IPV4_DST, Value: &ofp.OfpOxmOfbField_Ipv4Dst{Ipv4Dst: ipv4Dst}}
199}
200
201func TcpSrc(tcpSrc uint32) *ofp.OfpOxmOfbField {
202 return &ofp.OfpOxmOfbField{Type: TCP_SRC, Value: &ofp.OfpOxmOfbField_TcpSrc{TcpSrc: tcpSrc}}
203}
204
205func TcpDst(tcpDst uint32) *ofp.OfpOxmOfbField {
206 return &ofp.OfpOxmOfbField{Type: TCP_DST, Value: &ofp.OfpOxmOfbField_TcpDst{TcpDst: tcpDst}}
207}
208
209func UdpSrc(udpSrc uint32) *ofp.OfpOxmOfbField {
210 return &ofp.OfpOxmOfbField{Type: UDP_SRC, Value: &ofp.OfpOxmOfbField_UdpSrc{UdpSrc: udpSrc}}
211}
212
213func UdpDst(udpDst uint32) *ofp.OfpOxmOfbField {
214 return &ofp.OfpOxmOfbField{Type: UDP_DST, Value: &ofp.OfpOxmOfbField_UdpDst{UdpDst: udpDst}}
215}
216
217func SctpSrc(sctpSrc uint32) *ofp.OfpOxmOfbField {
218 return &ofp.OfpOxmOfbField{Type: SCTP_SRC, Value: &ofp.OfpOxmOfbField_SctpSrc{SctpSrc: sctpSrc}}
219}
220
221func SctpDst(sctpDst uint32) *ofp.OfpOxmOfbField {
222 return &ofp.OfpOxmOfbField{Type: SCTP_DST, Value: &ofp.OfpOxmOfbField_SctpDst{SctpDst: sctpDst}}
223}
224
225func Icmpv4Type(icmpv4Type uint32) *ofp.OfpOxmOfbField {
226 return &ofp.OfpOxmOfbField{Type: ICMPV4_TYPE, Value: &ofp.OfpOxmOfbField_Icmpv4Type{Icmpv4Type: icmpv4Type}}
227}
228
229func Icmpv4Code(icmpv4Code uint32) *ofp.OfpOxmOfbField {
230 return &ofp.OfpOxmOfbField{Type: ICMPV4_CODE, Value: &ofp.OfpOxmOfbField_Icmpv4Code{Icmpv4Code: icmpv4Code}}
231}
232
233func ArpOp(arpOp uint32) *ofp.OfpOxmOfbField {
234 return &ofp.OfpOxmOfbField{Type: ARP_OP, Value: &ofp.OfpOxmOfbField_ArpOp{ArpOp: arpOp}}
235}
236
237func ArpSpa(arpSpa uint32) *ofp.OfpOxmOfbField {
238 return &ofp.OfpOxmOfbField{Type: ARP_SPA, Value: &ofp.OfpOxmOfbField_ArpSpa{ArpSpa: arpSpa}}
239}
240
241func ArpTpa(arpTpa uint32) *ofp.OfpOxmOfbField {
242 return &ofp.OfpOxmOfbField{Type: ARP_TPA, Value: &ofp.OfpOxmOfbField_ArpTpa{ArpTpa: arpTpa}}
243}
244
245func ArpSha(arpSha []byte) *ofp.OfpOxmOfbField {
246 return &ofp.OfpOxmOfbField{Type: ARP_SHA, Value: &ofp.OfpOxmOfbField_ArpSha{ArpSha: arpSha}}
247}
248
249func ArpTha(arpTha []byte) *ofp.OfpOxmOfbField {
250 return &ofp.OfpOxmOfbField{Type: ARP_THA, Value: &ofp.OfpOxmOfbField_ArpTha{ArpTha: arpTha}}
251}
252
253func Ipv6Src(ipv6Src []byte) *ofp.OfpOxmOfbField {
254 return &ofp.OfpOxmOfbField{Type: IPV6_SRC, Value: &ofp.OfpOxmOfbField_Ipv6Src{Ipv6Src: ipv6Src}}
255}
256
257func Ipv6Dst(ipv6Dst []byte) *ofp.OfpOxmOfbField {
258 return &ofp.OfpOxmOfbField{Type: IPV6_DST, Value: &ofp.OfpOxmOfbField_Ipv6Dst{Ipv6Dst: ipv6Dst}}
259}
260
261func Ipv6Flabel(ipv6Flabel uint32) *ofp.OfpOxmOfbField {
262 return &ofp.OfpOxmOfbField{Type: IPV6_FLABEL, Value: &ofp.OfpOxmOfbField_Ipv6Flabel{Ipv6Flabel: ipv6Flabel}}
263}
264
265func Icmpv6Type(icmpv6Type uint32) *ofp.OfpOxmOfbField {
266 return &ofp.OfpOxmOfbField{Type: ICMPV6_TYPE, Value: &ofp.OfpOxmOfbField_Icmpv6Type{Icmpv6Type: icmpv6Type}}
267}
268
269func Icmpv6Code(icmpv6Code uint32) *ofp.OfpOxmOfbField {
270 return &ofp.OfpOxmOfbField{Type: ICMPV6_CODE, Value: &ofp.OfpOxmOfbField_Icmpv6Code{Icmpv6Code: icmpv6Code}}
271}
272
273func Ipv6NdTarget(ipv6NdTarget []byte) *ofp.OfpOxmOfbField {
274 return &ofp.OfpOxmOfbField{Type: IPV6_ND_TARGET, Value: &ofp.OfpOxmOfbField_Ipv6NdTarget{Ipv6NdTarget: ipv6NdTarget}}
275}
276
277func OfbIpv6NdSll(ofbIpv6NdSll []byte) *ofp.OfpOxmOfbField {
278 return &ofp.OfpOxmOfbField{Type: OFB_IPV6_ND_SLL, Value: &ofp.OfpOxmOfbField_Ipv6NdSsl{Ipv6NdSsl: ofbIpv6NdSll}}
279}
280
281func Ipv6NdTll(ipv6NdTll []byte) *ofp.OfpOxmOfbField {
282 return &ofp.OfpOxmOfbField{Type: IPV6_ND_TLL, Value: &ofp.OfpOxmOfbField_Ipv6NdTll{Ipv6NdTll: ipv6NdTll}}
283}
284
285func MplsLabel(mplsLabel uint32) *ofp.OfpOxmOfbField {
286 return &ofp.OfpOxmOfbField{Type: MPLS_LABEL, Value: &ofp.OfpOxmOfbField_MplsLabel{MplsLabel: mplsLabel}}
287}
288
289func MplsTc(mplsTc uint32) *ofp.OfpOxmOfbField {
290 return &ofp.OfpOxmOfbField{Type: MPLS_TC, Value: &ofp.OfpOxmOfbField_MplsTc{MplsTc: mplsTc}}
291}
292
293func MplsBos(mplsBos uint32) *ofp.OfpOxmOfbField {
294 return &ofp.OfpOxmOfbField{Type: MPLS_BOS, Value: &ofp.OfpOxmOfbField_MplsBos{MplsBos: mplsBos}}
295}
296
297func PbbIsid(pbbIsid uint32) *ofp.OfpOxmOfbField {
298 return &ofp.OfpOxmOfbField{Type: PBB_ISID, Value: &ofp.OfpOxmOfbField_PbbIsid{PbbIsid: pbbIsid}}
299}
300
301func TunnelId(tunnelId uint64) *ofp.OfpOxmOfbField {
302 return &ofp.OfpOxmOfbField{Type: TUNNEL_ID, Value: &ofp.OfpOxmOfbField_TunnelId{TunnelId: tunnelId}}
303}
304
305func Ipv6Exthdr(ipv6Exthdr uint32) *ofp.OfpOxmOfbField {
306 return &ofp.OfpOxmOfbField{Type: IPV6_EXTHDR, Value: &ofp.OfpOxmOfbField_Ipv6Exthdr{Ipv6Exthdr: ipv6Exthdr}}
307}
308
309//frequently used extractors
310
311func GetActions(flow *ofp.OfpFlowStats) []*ofp.OfpAction {
312 if flow == nil {
313 return nil
314 }
315 for _, instruction := range flow.Instructions {
316 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
317 instActions := instruction.GetActions()
318 if instActions == nil {
319 return nil
320 }
321 return instActions.Actions
322 }
323 }
324 return nil
325}
326
327func GetOfbFields(flow *ofp.OfpFlowStats) []*ofp.OfpOxmOfbField {
328 if flow == nil || flow.Match == nil || flow.Match.Type != ofp.OfpMatchType_OFPMT_OXM {
329 return nil
330 }
331 ofbFields := make([]*ofp.OfpOxmOfbField, 0)
332 for _, field := range flow.Match.OxmFields {
333 if field.OxmClass == ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
334 ofbFields = append(ofbFields, field.GetOfbField())
335 }
336 }
337 return ofbFields
338}
339
340func GetOutPort(flow *ofp.OfpFlowStats) uint32 {
341 if flow == nil {
342 return 0
343 }
344 for _, action := range GetActions(flow) {
345 if action.Type == OUTPUT {
346 out := action.GetOutput()
347 if out == nil {
348 return 0
349 }
350 return out.GetPort()
351 }
352 }
353 return 0
354}
355
356func GetInPort(flow *ofp.OfpFlowStats) uint32 {
357 if flow == nil {
358 return 0
359 }
360 for _, field := range GetOfbFields(flow) {
361 if field.Type == IN_PORT {
362 return field.GetPort()
363 }
364 }
365 return 0
366}
367
368func GetGotoTableId(flow *ofp.OfpFlowStats) uint32 {
369 if flow == nil {
370 return 0
371 }
372 for _, instruction := range flow.Instructions {
373 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE) {
374 gotoTable := instruction.GetGotoTable()
375 if gotoTable == nil {
376 return 0
377 }
378 return gotoTable.GetTableId()
379 }
380 }
381 return 0
382}
383
384//GetMetaData - legacy get method (only want lower 32 bits)
385func GetMetaData(flow *ofp.OfpFlowStats) uint32 {
386 if flow == nil {
387 return 0
388 }
389 for _, field := range GetOfbFields(flow) {
390 if field.Type == METADATA {
391 return uint32(field.GetTableMetadata() & 0xffffffff)
392 }
393 }
394 return 0
395}
396
397func GetMetaData64Bit(flow *ofp.OfpFlowStats) uint64 {
398 if flow == nil {
399 return 0
400 }
401 for _, field := range GetOfbFields(flow) {
402 if field.Type == METADATA {
403 return field.GetTableMetadata()
404 }
405 }
406 return 0
407}
408
409// GetPortNumberFromMetadata retrieves the port number from the Metadata_ofp. The port number (UNI on ONU) is in the
410// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
411// a Metadata_ofp field
412func GetPortNumberFromMetadata(flow *ofp.OfpFlowStats) uint64 {
413 md := GetMetaData64Bit(flow)
414 if md == 0 {
415 return 0
416 }
417 if md <= 0xffffffff {
418 log.Warnw("onos-upgrade-suggested", log.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
419 return md
420 }
421 return md & 0xffffffff
422}
423
424//GetInnerTagFromMetaData retrieves the inner tag from the Metadata_ofp. The port number (UNI on ONU) is in the
425// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
426//// a Metadata_ofp field
427func GetInnerTagFromMetaData(flow *ofp.OfpFlowStats) uint64 {
428 md := GetMetaData64Bit(flow)
429 if md == 0 {
430 return 0
431 }
432 if md <= 0xffffffff {
433 log.Warnw("onos-upgrade-suggested", log.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
434 return md
435 }
436 return (md >> 32) & 0xffffffff
437}
438
439func HasNextTable(flow *ofp.OfpFlowStats) bool {
440 if flow == nil {
441 return false
442 }
443 return GetGotoTableId(flow) != 0
444}
445
446func GetGroup(flow *ofp.OfpFlowStats) uint32 {
447 if flow == nil {
448 return 0
449 }
450 for _, action := range GetActions(flow) {
451 if action.Type == GROUP {
452 grp := action.GetGroup()
453 if grp == nil {
454 return 0
455 }
456 return grp.GetGroupId()
457 }
458 }
459 return 0
460}
461
462func HasGroup(flow *ofp.OfpFlowStats) bool {
463 return GetGroup(flow) != 0
464}
465
466// GetNextTableId returns the next table ID if the "table_id" is present in the map, otherwise return nil
467func GetNextTableId(kw fu.OfpFlowModArgs) *uint32 {
468 if val, exist := kw["table_id"]; exist {
469 ret := uint32(val)
470 return &ret
471 }
472 return nil
473}
474
475// Return unique 64-bit integer hash for flow covering the following attributes:
476// 'table_id', 'priority', 'flags', 'cookie', 'match', '_instruction_string'
477func hashFlowStats(flow *ofp.OfpFlowStats) uint64 {
478 if flow == nil { // Should never happen
479 return 0
480 }
481 // Create string with the instructions field first
482 var instructionString bytes.Buffer
483 for _, instruction := range flow.Instructions {
484 instructionString.WriteString(instruction.String())
485 }
486 var flowString = fmt.Sprintf("%d%d%d%d%s%s", flow.TableId, flow.Priority, flow.Flags, flow.Cookie, flow.Match.String(), instructionString.String())
487 h := md5.New()
488 h.Write([]byte(flowString))
489 hash := big.NewInt(0)
490 hash.SetBytes(h.Sum(nil))
491 return hash.Uint64()
492}
493
494// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
495func FlowStatsEntryFromFlowModMessage(mod *ofp.OfpFlowMod) *ofp.OfpFlowStats {
496 flow := &ofp.OfpFlowStats{}
497 if mod == nil {
498 return flow
499 }
500 flow.TableId = mod.TableId
501 flow.Priority = mod.Priority
502 flow.IdleTimeout = mod.IdleTimeout
503 flow.HardTimeout = mod.HardTimeout
504 flow.Flags = mod.Flags
505 flow.Cookie = mod.Cookie
506 flow.Match = mod.Match
507 flow.Instructions = mod.Instructions
508 flow.Id = hashFlowStats(flow)
509 return flow
510}
511
512func GroupEntryFromGroupMod(mod *ofp.OfpGroupMod) *ofp.OfpGroupEntry {
513 group := &ofp.OfpGroupEntry{}
514 if mod == nil {
515 return group
516 }
517 group.Desc = &ofp.OfpGroupDesc{Type: mod.Type, GroupId: mod.GroupId, Buckets: mod.Buckets}
518 group.Stats = &ofp.OfpGroupStats{GroupId: mod.GroupId}
519 return group
520}
521
522func MkOxmFields(matchFields []ofp.OfpOxmField) []*ofp.OfpOxmField {
523 oxmFields := make([]*ofp.OfpOxmField, 0)
524 for _, matchField := range matchFields {
525 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
526 oxmFields = append(oxmFields, &oxmField)
527 }
528 return oxmFields
529}
530
531func MkInstructionsFromActions(actions []*ofp.OfpAction) []*ofp.OfpInstruction {
532 instructions := make([]*ofp.OfpInstruction, 0)
533 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
534 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
535 instructions = append(instructions, &instruction)
536 return instructions
537}
538
539// Convenience function to generare ofp_flow_mod message with OXM BASIC match composed from the match_fields, and
540// single APPLY_ACTIONS instruction with a list if ofp_action objects.
541func MkSimpleFlowMod(matchFields []*ofp.OfpOxmField, actions []*ofp.OfpAction, command *ofp.OfpFlowModCommand, kw fu.OfpFlowModArgs) *ofp.OfpFlowMod {
542
543 // Process actions instructions
544 instructions := make([]*ofp.OfpInstruction, 0)
545 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
546 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
547 instructions = append(instructions, &instruction)
548
549 // Process next table
550 if tableId := GetNextTableId(kw); tableId != nil {
551 var instGotoTable ofp.OfpInstruction_GotoTable
552 instGotoTable.GotoTable = &ofp.OfpInstructionGotoTable{TableId: *tableId}
553 inst := ofp.OfpInstruction{Type: uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE), Data: &instGotoTable}
554 instructions = append(instructions, &inst)
555 }
556
557 // Process match fields
558 oxmFields := make([]*ofp.OfpOxmField, 0)
559 for _, matchField := range matchFields {
560 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
561 oxmFields = append(oxmFields, &oxmField)
562 }
563 var match ofp.OfpMatch
564 match.Type = ofp.OfpMatchType_OFPMT_OXM
565 match.OxmFields = oxmFields
566
567 // Create ofp_flow_message
568 msg := &ofp.OfpFlowMod{}
569 if command == nil {
570 msg.Command = ofp.OfpFlowModCommand_OFPFC_ADD
571 } else {
572 msg.Command = *command
573 }
574 msg.Instructions = instructions
575 msg.Match = &match
576
577 // Set the variadic argument values
578 msg = setVariadicModAttributes(msg, kw)
579
580 return msg
581}
582
583func MkMulticastGroupMod(groupId uint32, buckets []*ofp.OfpBucket, command *ofp.OfpGroupModCommand) *ofp.OfpGroupMod {
584 group := &ofp.OfpGroupMod{}
585 if command == nil {
586 group.Command = ofp.OfpGroupModCommand_OFPGC_ADD
587 } else {
588 group.Command = *command
589 }
590 group.Type = ofp.OfpGroupType_OFPGT_ALL
591 group.GroupId = groupId
592 group.Buckets = buckets
593 return group
594}
595
596//SetVariadicModAttributes sets only uint64 or uint32 fields of the ofp_flow_mod message
597func setVariadicModAttributes(mod *ofp.OfpFlowMod, args fu.OfpFlowModArgs) *ofp.OfpFlowMod {
598 if args == nil {
599 return mod
600 }
601 for key, val := range args {
602 switch key {
603 case "cookie":
604 mod.Cookie = val
605 case "cookie_mask":
606 mod.CookieMask = val
607 case "table_id":
608 mod.TableId = uint32(val)
609 case "idle_timeout":
610 mod.IdleTimeout = uint32(val)
611 case "hard_timeout":
612 mod.HardTimeout = uint32(val)
613 case "priority":
614 mod.Priority = uint32(val)
615 case "buffer_id":
616 mod.BufferId = uint32(val)
617 case "out_port":
618 mod.OutPort = uint32(val)
619 case "out_group":
620 mod.OutGroup = uint32(val)
621 case "flags":
622 mod.Flags = uint32(val)
623 }
624 }
625 return mod
626}
627
628// MkFlowStat is a helper method to build flows
629func MkFlowStat(fa *fu.FlowArgs) *ofp.OfpFlowStats {
630 //Build the matchfields
631 matchFields := make([]*ofp.OfpOxmField, 0)
632 for _, val := range fa.MatchFields {
633 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
634 }
635 return FlowStatsEntryFromFlowModMessage(MkSimpleFlowMod(matchFields, fa.Actions, fa.Command, fa.KV))
636}
637
638func MkGroupStat(groupId uint32, buckets []*ofp.OfpBucket, command *ofp.OfpGroupModCommand) *ofp.OfpGroupEntry {
639 return GroupEntryFromGroupMod(MkMulticastGroupMod(groupId, buckets, command))
640}
641
642type FlowDecomposer struct {
643 deviceMgr coreIf.DeviceManager
644}
645
646func NewFlowDecomposer(deviceMgr coreIf.DeviceManager) *FlowDecomposer {
647 var decomposer FlowDecomposer
648 decomposer.deviceMgr = deviceMgr
649 return &decomposer
650}
651
652//DecomposeRules decomposes per-device flows and flow-groups from the flows and groups defined on a logical device
653func (fd *FlowDecomposer) DecomposeRules(agent coreIf.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups) *fu.DeviceRules {
654 rules := agent.GetAllDefaultRules()
655 deviceRules := rules.Copy()
656
657 groupMap := make(map[uint32]*ofp.OfpGroupEntry)
658 for _, groupEntry := range groups.Items {
659 groupMap[groupEntry.Desc.GroupId] = groupEntry
660 }
661
662 var decomposedRules *fu.DeviceRules
663 for _, flow := range flows.Items {
664 decomposedRules = fd.decomposeFlow(agent, flow, groupMap)
665 for deviceId, flowAndGroups := range decomposedRules.Rules {
666 fmt.Println("!!!!!", deviceId, flowAndGroups)
667 deviceRules.Rules[deviceId] = fu.NewFlowsAndGroups()
668 deviceRules.Rules[deviceId].AddFrom(flowAndGroups)
669 }
670 }
671 return deviceRules
672}
673
674func (fd *FlowDecomposer) processControllerBoundFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules) *fu.DeviceRules {
675 log.Debugw("trap-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "flow": flow})
676 fg := fu.NewFlowsAndGroups()
677 if agent.GetDeviceGraph().IsRootPort(inPortNo) {
678 log.Debug("trap-nni")
679 var fa *fu.FlowArgs
680 fa = &fu.FlowArgs{
681 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
682 MatchFields: []*ofp.OfpOxmOfbField{
683 InPort(route[1].Egress), //egress_hop.egress_port.port_no
684 },
685 Actions: GetActions(flow),
686 }
687 // Augment the matchfields with the ofpfields from the flow
688 for _, val := range GetOfbFields(flow) {
689 if val.Type != IN_PORT {
690 fa.MatchFields = append(fa.MatchFields, val)
691 }
692 }
693 fg.AddFlow(MkFlowStat(fa))
694 } else {
695 // Trap flow for UNI port
696 log.Debug("trap-uni")
697
698 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
699 var inPorts []uint32
700 if inPortNo == 0 {
701 inPorts = agent.GetWildcardInputPorts(route[1].Egress) // exclude egress_hop.egress_port.port_no
702 } else {
703 inPorts = []uint32{inPortNo}
704 }
705 for _, inputPort := range inPorts {
706 var fa *fu.FlowArgs
707 // Upstream flow
708 fa = &fu.FlowArgs{
709 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
710 MatchFields: []*ofp.OfpOxmOfbField{
711 InPort(route[1].Ingress), //egress_hop.ingress_port.port_no
712 VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | inputPort),
713 },
714 Actions: []*ofp.OfpAction{
715 PushVlan(0x8100),
716 SetField(VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
717 Output(route[1].Egress),
718 },
719 }
720 // Augment the matchfields with the ofpfields from the flow
721 for _, val := range GetOfbFields(flow) {
722 if val.Type != IN_PORT && val.Type != VLAN_VID {
723 fa.MatchFields = append(fa.MatchFields, val)
724 }
725 }
726 fg.AddFlow(MkFlowStat(fa))
727
728 // Downstream flow
729 fa = &fu.FlowArgs{
730 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority)},
731 MatchFields: []*ofp.OfpOxmOfbField{
732 InPort(route[1].Egress), //egress_hop.ingress_port.port_no
733 VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000),
734 VlanPcp(0),
735 Metadata_ofp(uint64(inputPort)),
736 },
737 Actions: []*ofp.OfpAction{
738 PopVlan(),
739 Output(route[1].Ingress),
740 },
741 }
742 fg.AddFlow(MkFlowStat(fa))
743 }
744 }
745 deviceRules.AddFlowsAndGroup(route[1].DeviceID, fg)
746 return deviceRules
747}
748
749// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
750// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
751// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
752// applied at the OLT
753func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules) *fu.DeviceRules {
754 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
755 if HasNextTable(flow) {
756 log.Debugw("has-next-table", log.Fields{"table_id": flow.TableId})
757 if outPortNo != 0 {
758 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
759 }
760 var fa *fu.FlowArgs
761 fa = &fu.FlowArgs{
762 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
763 MatchFields: []*ofp.OfpOxmOfbField{
764 InPort(route[0].Ingress), //ingress_hop.ingress_port.port_no
765 },
766 Actions: GetActions(flow),
767 }
768 // Augment the matchfields with the ofpfields from the flow
769 for _, val := range GetOfbFields(flow) {
770 if val.Type != IN_PORT {
771 fa.MatchFields = append(fa.MatchFields, val)
772 }
773 }
774 // Agument the Actions
775 fa.Actions = append(fa.Actions, Output(route[0].Egress))
776 fg := fu.NewFlowsAndGroups()
777 fg.AddFlow(MkFlowStat(fa))
778 deviceRules.AddFlowsAndGroup(route[0].DeviceID, fg)
779 } else {
780 var actions []ofp.OfpActionType
781 var isOutputTypeInActions bool
782 for _, action := range GetActions(flow) {
783 actions = append(actions, action.Type)
784 if !isOutputTypeInActions && action.Type == OUTPUT {
785 isOutputTypeInActions = true
786 }
787 }
788 if len(actions) == 1 && isOutputTypeInActions {
789 var fa *fu.FlowArgs
790 // child device flow
791 fa = &fu.FlowArgs{
792 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
793 MatchFields: []*ofp.OfpOxmOfbField{
794 InPort(route[0].Ingress), //ingress_hop.ingress_port.port_no
795 },
796 Actions: []*ofp.OfpAction{
797 Output(route[0].Egress),
798 },
799 }
800 // Augment the matchfields with the ofpfields from the flow
801 for _, val := range GetOfbFields(flow) {
802 if val.Type != IN_PORT {
803 fa.MatchFields = append(fa.MatchFields, val)
804 }
805 }
806 fg := fu.NewFlowsAndGroups()
807 fg.AddFlow(MkFlowStat(fa))
808 deviceRules.AddFlowsAndGroup(route[0].DeviceID, fg)
809
810 // parent device flow
811 fa = &fu.FlowArgs{
812 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
813 MatchFields: []*ofp.OfpOxmOfbField{
814 InPort(route[1].Ingress), //egress_hop.ingress_port.port_no
815 },
816 Actions: []*ofp.OfpAction{
817 Output(route[1].Egress),
818 },
819 }
820 // Augment the matchfields with the ofpfields from the flow
821 for _, val := range GetOfbFields(flow) {
822 if val.Type != IN_PORT {
823 fa.MatchFields = append(fa.MatchFields, val)
824 }
825 }
826 fg = fu.NewFlowsAndGroups()
827 fg.AddFlow(MkFlowStat(fa))
828 deviceRules.AddFlowsAndGroup(route[1].DeviceID, fg)
829 } else {
830 if outPortNo == 0 {
831 log.Warnw("outPort-should-be-specified", log.Fields{"outPortNo": outPortNo})
832 }
833 var fa *fu.FlowArgs
834 fa = &fu.FlowArgs{
835 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
836 MatchFields: []*ofp.OfpOxmOfbField{
837 InPort(route[1].Ingress), //egress_hop.ingress_port.port_no
838 },
839 }
840 // Augment the matchfields with the ofpfields from the flow
841 for _, val := range GetOfbFields(flow) {
842 if val.Type != IN_PORT {
843 fa.MatchFields = append(fa.MatchFields, val)
844 }
845 }
846 // Augment the Actions
847 updatedAction := make([]*ofp.OfpAction, 0)
848 for _, action := range GetActions(flow) {
849 if action.Type != OUTPUT {
850 updatedAction = append(updatedAction, action)
851 }
852 }
853 updatedAction = append(updatedAction, Output(route[1].Egress))
854 fa.Actions = updatedAction
855 fg := fu.NewFlowsAndGroups()
856 fg.AddFlow(MkFlowStat(fa))
857 deviceRules.AddFlowsAndGroup(route[1].DeviceID, fg)
858 }
859 }
860 return deviceRules
861}
862
863func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules) *fu.DeviceRules {
864 log.Debugw("downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
865 if outPortNo != 0 {
866 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
867 }
868 ingressHop := route[0]
869 if GetMetaData(flow) != 0 {
870 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
871 portNumber := uint32(GetPortNumberFromMetadata(flow))
872 if portNumber != 0 {
873 recalculatedRoute := agent.GetRoute(&inPortNo, &portNumber)
874 switch len(recalculatedRoute) {
875 case 0:
876 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": GetMetaData64Bit(flow)})
877 // TODO: Delete flow
878 return deviceRules
879 case 2:
880 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
881 break
882 default:
883 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
884 return deviceRules
885 }
886 ingressHop = recalculatedRoute[0]
887 }
888 innerTag := GetInnerTagFromMetaData(flow)
889 if innerTag == 0 {
890 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": GetMetaData64Bit(flow)})
891 // TODO: Delete flow
892 return deviceRules
893 }
894 var fa *fu.FlowArgs
895 fa = &fu.FlowArgs{
896 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
897 MatchFields: []*ofp.OfpOxmOfbField{
898 InPort(ingressHop.Ingress), //ingress_hop.ingress_port.port_no
899 Metadata_ofp(innerTag),
900 },
901 Actions: GetActions(flow),
902 }
903 // Augment the matchfields with the ofpfields from the flow
904 for _, val := range GetOfbFields(flow) {
905 if val.Type != IN_PORT && val.Type != METADATA {
906 fa.MatchFields = append(fa.MatchFields, val)
907 }
908 }
909 // Agument the Actions
910 fa.Actions = append(fa.Actions, Output(ingressHop.Egress))
911 fg := fu.NewFlowsAndGroups()
912 fg.AddFlow(MkFlowStat(fa))
913 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
914 } else { // Create standard flow
915 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
916 var fa *fu.FlowArgs
917 fa = &fu.FlowArgs{
918 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
919 MatchFields: []*ofp.OfpOxmOfbField{
920 InPort(ingressHop.Ingress), //ingress_hop.ingress_port.port_no
921 },
922 Actions: GetActions(flow),
923 }
924 // Augment the matchfields with the ofpfields from the flow
925 for _, val := range GetOfbFields(flow) {
926 if val.Type != IN_PORT {
927 fa.MatchFields = append(fa.MatchFields, val)
928 }
929 }
930 // Agument the Actions
931 fa.Actions = append(fa.Actions, Output(ingressHop.Egress))
932 fg := fu.NewFlowsAndGroups()
933 fg.AddFlow(MkFlowStat(fa))
934 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
935 }
936 return deviceRules
937}
938
939func (fd *FlowDecomposer) processUnicastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules) *fu.DeviceRules {
940 log.Debugw("unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
941 var actions []ofp.OfpActionType
942 var isOutputTypeInActions bool
943 for _, action := range GetActions(flow) {
944 actions = append(actions, action.Type)
945 if !isOutputTypeInActions && action.Type == OUTPUT {
946 isOutputTypeInActions = true
947 }
948 }
949 if len(actions) == 1 && isOutputTypeInActions {
950 var fa *fu.FlowArgs
951 // Parent device flow
952 fa = &fu.FlowArgs{
953 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
954 MatchFields: []*ofp.OfpOxmOfbField{
955 InPort(route[0].Ingress), //ingress_hop.ingress_port.port_no
956 },
957 Actions: []*ofp.OfpAction{
958 Output(route[0].Egress),
959 },
960 }
961 // Augment the matchfields with the ofpfields from the flow
962 for _, val := range GetOfbFields(flow) {
963 if val.Type != IN_PORT {
964 fa.MatchFields = append(fa.MatchFields, val)
965 }
966 }
967 fg := fu.NewFlowsAndGroups()
968 fg.AddFlow(MkFlowStat(fa))
969 deviceRules.AddFlowsAndGroup(route[0].DeviceID, fg)
970
971 // Child device flow
972 fa = &fu.FlowArgs{
973 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
974 MatchFields: []*ofp.OfpOxmOfbField{
975 InPort(route[1].Ingress), //egress_hop.ingress_port.port_no
976 },
977 Actions: []*ofp.OfpAction{
978 Output(route[1].Egress),
979 },
980 }
981 // Augment the matchfields with the ofpfields from the flow
982 for _, val := range GetOfbFields(flow) {
983 if val.Type != IN_PORT {
984 fa.MatchFields = append(fa.MatchFields, val)
985 }
986 }
987 fg = fu.NewFlowsAndGroups()
988 fg.AddFlow(MkFlowStat(fa))
989 deviceRules.AddFlowsAndGroup(route[1].DeviceID, fg)
990 } else {
991 var fa *fu.FlowArgs
992 fa = &fu.FlowArgs{
993 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
994 MatchFields: []*ofp.OfpOxmOfbField{
995 InPort(route[1].Ingress), //egress_hop.ingress_port.port_no
996 },
997 }
998 // Augment the matchfields with the ofpfields from the flow
999 for _, val := range GetOfbFields(flow) {
1000 if val.Type != IN_PORT {
1001 fa.MatchFields = append(fa.MatchFields, val)
1002 }
1003 }
1004 // Augment the Actions
1005 updatedAction := make([]*ofp.OfpAction, 0)
1006 for _, action := range GetActions(flow) {
1007 if action.Type != OUTPUT {
1008 updatedAction = append(updatedAction, action)
1009 }
1010 }
1011 updatedAction = append(updatedAction, Output(route[1].Egress))
1012 fa.Actions = updatedAction
1013 fg := fu.NewFlowsAndGroups()
1014 fg.AddFlow(MkFlowStat(fa))
1015 deviceRules.AddFlowsAndGroup(route[1].DeviceID, fg)
1016 }
1017 return deviceRules
1018}
1019
1020func (fd *FlowDecomposer) processMulticastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules, grpId uint32, groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
1021 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
1022
1023 //having no Group yet is the same as having a Group with no buckets
1024 var grp *ofp.OfpGroupEntry
1025 var ok bool
1026 if grp, ok = groupMap[grpId]; !ok {
1027 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpId, "groupMap": groupMap})
1028 return deviceRules
1029 }
1030 if grp == nil || grp.Desc == nil {
1031 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpId, "grp": grp})
1032 return deviceRules
1033 }
1034 for _, bucket := range grp.Desc.Buckets {
1035 otherActions := make([]*ofp.OfpAction, 0)
1036 for _, action := range bucket.Actions {
1037 if action.Type == OUTPUT {
1038 outPortNo = action.GetOutput().Port
1039 } else if action.Type != POP_VLAN {
1040 otherActions = append(otherActions, action)
1041 }
1042 }
1043
1044 route2 := agent.GetRoute(&inPortNo, &outPortNo)
1045 switch len(route2) {
1046 case 0:
1047 log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"})
1048 // TODO: Delete flow
1049 return deviceRules
1050 case 2:
1051 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
1052 break
1053 default:
1054 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
1055 return deviceRules
1056 }
1057
1058 if route[0].Ingress != route2[0].Ingress {
1059 log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"})
1060 return deviceRules
1061 }
1062 // Set the parent device flow
1063 var fa *fu.FlowArgs
1064 fa = &fu.FlowArgs{
1065 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1066 MatchFields: []*ofp.OfpOxmOfbField{
1067 InPort(route[0].Ingress), //ingress_hop.ingress_port.port_no
1068 },
1069 }
1070 // Augment the matchfields with the ofpfields from the flow
1071 for _, val := range GetOfbFields(flow) {
1072 if val.Type != IN_PORT {
1073 fa.MatchFields = append(fa.MatchFields, val)
1074 }
1075 }
1076 // Augment the Actions
1077 updatedAction := make([]*ofp.OfpAction, 0)
1078 for _, action := range GetActions(flow) {
1079 if action.Type != GROUP {
1080 updatedAction = append(updatedAction, action)
1081 }
1082 }
1083 updatedAction = append(updatedAction, PopVlan())
1084 updatedAction = append(updatedAction, Output(route[1].Ingress))
1085 fa.Actions = updatedAction
1086 fg := fu.NewFlowsAndGroups()
1087 fg.AddFlow(MkFlowStat(fa))
1088 deviceRules.AddFlowsAndGroup(route[0].DeviceID, fg)
1089
1090 // Set the child device flow
1091 fa = &fu.FlowArgs{
1092 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1093 MatchFields: []*ofp.OfpOxmOfbField{
1094 InPort(route[1].Ingress), //egress_hop.ingress_port.port_no
1095 },
1096 }
1097 // Augment the matchfields with the ofpfields from the flow
1098 for _, val := range GetOfbFields(flow) {
1099 if val.Type != IN_PORT && val.Type != VLAN_VID && val.Type != VLAN_PCP {
1100 fa.MatchFields = append(fa.MatchFields, val)
1101 }
1102 }
1103 // Augment the Actions
1104 otherActions = append(otherActions, Output(route[1].Egress))
1105 fa.Actions = otherActions
1106 fg = fu.NewFlowsAndGroups()
1107 fg.AddFlow(MkFlowStat(fa))
1108 deviceRules.AddFlowsAndGroup(route[1].DeviceID, fg)
1109 }
1110 return deviceRules
1111}
1112
1113func (fd *FlowDecomposer) decomposeFlow(agent coreIf.LogicalDeviceAgent, flow *ofp.OfpFlowStats, groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
1114 inPortNo := GetInPort(flow)
1115 outPortNo := GetOutPort(flow)
1116
1117 deviceRules := fu.NewDeviceRules()
1118
1119 route := agent.GetRoute(&inPortNo, &outPortNo)
1120 switch len(route) {
1121 case 0:
1122 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"})
1123 // TODO: Delete flow
1124 return deviceRules
1125 case 2:
1126 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
1127 break
1128 default:
1129 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
1130 return deviceRules
1131 }
1132
1133 var ingressDevice *voltha.Device
1134 //var egressDevice *voltha.Device
1135 var err error
1136 if ingressDevice, err = fd.deviceMgr.GetDevice(route[0].DeviceID); err != nil {
1137 log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID})
1138 return deviceRules
1139 }
1140 //if egressDevice, err = fd.deviceMgr.getDevice(route[1].DeviceID); err != nil {
1141 // log.Errorw("egress-device-not-found", log.Fields{"deviceId": route[1].DeviceID})
1142 // return deviceRules
1143 //}
1144
1145 isDownstream := ingressDevice.Root
1146 isUpstream := !isDownstream
1147
1148 // Process controller bound flow
1149 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
1150 deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow, deviceRules)
1151 } else {
1152 if isUpstream {
1153 deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow, deviceRules)
1154 } else if HasNextTable(flow) {
1155 deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow, deviceRules)
1156 } else if outPortNo != 0 { // Unicast
1157 deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow, deviceRules)
1158 } else if grpId := GetGroup(flow); grpId != 0 { //Multicast
1159 deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, deviceRules, grpId, groupMap)
1160 }
1161 }
1162 return deviceRules
1163}