blob: 233465bd473e69c7a9d897b28c5e6791b2a12b3a [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
khenaidood20a5852018-10-22 22:09:55 -0400311func excludeAction(action *ofp.OfpAction, exclude ...ofp.OfpActionType) bool {
312 for _, actionToExclude := range exclude {
313 if action.Type == actionToExclude {
314 return true
315 }
316 }
317 return false
318}
319
320func GetActions(flow *ofp.OfpFlowStats, exclude ...ofp.OfpActionType) []*ofp.OfpAction {
khenaidoo89b0e942018-10-21 21:11:33 -0400321 if flow == nil {
322 return nil
323 }
324 for _, instruction := range flow.Instructions {
325 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
326 instActions := instruction.GetActions()
327 if instActions == nil {
328 return nil
329 }
khenaidood20a5852018-10-22 22:09:55 -0400330 if len(exclude) == 0 {
331 return instActions.Actions
332 } else {
333 filteredAction := make([]*ofp.OfpAction, 0)
334 for _, action := range instActions.Actions {
335 if !excludeAction(action, exclude...) {
336 filteredAction = append(filteredAction, action)
337 }
338 }
339 return filteredAction
340 }
khenaidoo89b0e942018-10-21 21:11:33 -0400341 }
342 }
343 return nil
344}
345
khenaidood20a5852018-10-22 22:09:55 -0400346func excludeOxmOfbField(field *ofp.OfpOxmOfbField, exclude ...ofp.OxmOfbFieldTypes) bool {
347 for _, fieldToExclude := range exclude {
348 if field.Type == fieldToExclude {
349 return true
350 }
351 }
352 return false
353}
354
355func GetOfbFields(flow *ofp.OfpFlowStats, exclude ...ofp.OxmOfbFieldTypes) []*ofp.OfpOxmOfbField {
khenaidoo89b0e942018-10-21 21:11:33 -0400356 if flow == nil || flow.Match == nil || flow.Match.Type != ofp.OfpMatchType_OFPMT_OXM {
357 return nil
358 }
359 ofbFields := make([]*ofp.OfpOxmOfbField, 0)
360 for _, field := range flow.Match.OxmFields {
361 if field.OxmClass == ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
362 ofbFields = append(ofbFields, field.GetOfbField())
363 }
364 }
khenaidood20a5852018-10-22 22:09:55 -0400365 if len(exclude) == 0 {
366 return ofbFields
367 } else {
368 filteredFields := make([]*ofp.OfpOxmOfbField, 0)
369 for _, ofbField := range ofbFields {
370 if !excludeOxmOfbField(ofbField, exclude...) {
371 filteredFields = append(filteredFields, ofbField)
372 }
373 }
374 return filteredFields
375 }
khenaidoo89b0e942018-10-21 21:11:33 -0400376}
377
378func GetOutPort(flow *ofp.OfpFlowStats) uint32 {
379 if flow == nil {
380 return 0
381 }
382 for _, action := range GetActions(flow) {
383 if action.Type == OUTPUT {
384 out := action.GetOutput()
385 if out == nil {
386 return 0
387 }
388 return out.GetPort()
389 }
390 }
391 return 0
392}
393
394func GetInPort(flow *ofp.OfpFlowStats) uint32 {
395 if flow == nil {
396 return 0
397 }
398 for _, field := range GetOfbFields(flow) {
399 if field.Type == IN_PORT {
400 return field.GetPort()
401 }
402 }
403 return 0
404}
405
406func GetGotoTableId(flow *ofp.OfpFlowStats) uint32 {
407 if flow == nil {
408 return 0
409 }
410 for _, instruction := range flow.Instructions {
411 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE) {
412 gotoTable := instruction.GetGotoTable()
413 if gotoTable == nil {
414 return 0
415 }
416 return gotoTable.GetTableId()
417 }
418 }
419 return 0
420}
421
422//GetMetaData - legacy get method (only want lower 32 bits)
423func GetMetaData(flow *ofp.OfpFlowStats) uint32 {
424 if flow == nil {
425 return 0
426 }
427 for _, field := range GetOfbFields(flow) {
428 if field.Type == METADATA {
429 return uint32(field.GetTableMetadata() & 0xffffffff)
430 }
431 }
432 return 0
433}
434
435func GetMetaData64Bit(flow *ofp.OfpFlowStats) uint64 {
436 if flow == nil {
437 return 0
438 }
439 for _, field := range GetOfbFields(flow) {
440 if field.Type == METADATA {
441 return field.GetTableMetadata()
442 }
443 }
444 return 0
445}
446
447// GetPortNumberFromMetadata retrieves the port number from the Metadata_ofp. The port number (UNI on ONU) is in the
448// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
449// a Metadata_ofp field
450func GetPortNumberFromMetadata(flow *ofp.OfpFlowStats) uint64 {
451 md := GetMetaData64Bit(flow)
452 if md == 0 {
453 return 0
454 }
455 if md <= 0xffffffff {
456 log.Warnw("onos-upgrade-suggested", log.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
457 return md
458 }
459 return md & 0xffffffff
460}
461
462//GetInnerTagFromMetaData retrieves the inner tag from the Metadata_ofp. The port number (UNI on ONU) is in the
463// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
464//// a Metadata_ofp field
465func GetInnerTagFromMetaData(flow *ofp.OfpFlowStats) uint64 {
466 md := GetMetaData64Bit(flow)
467 if md == 0 {
468 return 0
469 }
470 if md <= 0xffffffff {
471 log.Warnw("onos-upgrade-suggested", log.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
472 return md
473 }
474 return (md >> 32) & 0xffffffff
475}
476
477func HasNextTable(flow *ofp.OfpFlowStats) bool {
478 if flow == nil {
479 return false
480 }
481 return GetGotoTableId(flow) != 0
482}
483
484func GetGroup(flow *ofp.OfpFlowStats) uint32 {
485 if flow == nil {
486 return 0
487 }
488 for _, action := range GetActions(flow) {
489 if action.Type == GROUP {
490 grp := action.GetGroup()
491 if grp == nil {
492 return 0
493 }
494 return grp.GetGroupId()
495 }
496 }
497 return 0
498}
499
500func HasGroup(flow *ofp.OfpFlowStats) bool {
501 return GetGroup(flow) != 0
502}
503
504// GetNextTableId returns the next table ID if the "table_id" is present in the map, otherwise return nil
505func GetNextTableId(kw fu.OfpFlowModArgs) *uint32 {
506 if val, exist := kw["table_id"]; exist {
507 ret := uint32(val)
508 return &ret
509 }
510 return nil
511}
512
513// Return unique 64-bit integer hash for flow covering the following attributes:
514// 'table_id', 'priority', 'flags', 'cookie', 'match', '_instruction_string'
515func hashFlowStats(flow *ofp.OfpFlowStats) uint64 {
516 if flow == nil { // Should never happen
517 return 0
518 }
519 // Create string with the instructions field first
520 var instructionString bytes.Buffer
521 for _, instruction := range flow.Instructions {
522 instructionString.WriteString(instruction.String())
523 }
524 var flowString = fmt.Sprintf("%d%d%d%d%s%s", flow.TableId, flow.Priority, flow.Flags, flow.Cookie, flow.Match.String(), instructionString.String())
525 h := md5.New()
526 h.Write([]byte(flowString))
527 hash := big.NewInt(0)
528 hash.SetBytes(h.Sum(nil))
529 return hash.Uint64()
530}
531
532// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
533func FlowStatsEntryFromFlowModMessage(mod *ofp.OfpFlowMod) *ofp.OfpFlowStats {
534 flow := &ofp.OfpFlowStats{}
535 if mod == nil {
536 return flow
537 }
538 flow.TableId = mod.TableId
539 flow.Priority = mod.Priority
540 flow.IdleTimeout = mod.IdleTimeout
541 flow.HardTimeout = mod.HardTimeout
542 flow.Flags = mod.Flags
543 flow.Cookie = mod.Cookie
544 flow.Match = mod.Match
545 flow.Instructions = mod.Instructions
546 flow.Id = hashFlowStats(flow)
547 return flow
548}
549
550func GroupEntryFromGroupMod(mod *ofp.OfpGroupMod) *ofp.OfpGroupEntry {
551 group := &ofp.OfpGroupEntry{}
552 if mod == nil {
553 return group
554 }
555 group.Desc = &ofp.OfpGroupDesc{Type: mod.Type, GroupId: mod.GroupId, Buckets: mod.Buckets}
556 group.Stats = &ofp.OfpGroupStats{GroupId: mod.GroupId}
khenaidood20a5852018-10-22 22:09:55 -0400557 //TODO do we need to instantiate bucket bins?
khenaidoo89b0e942018-10-21 21:11:33 -0400558 return group
559}
560
561func MkOxmFields(matchFields []ofp.OfpOxmField) []*ofp.OfpOxmField {
562 oxmFields := make([]*ofp.OfpOxmField, 0)
563 for _, matchField := range matchFields {
564 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
565 oxmFields = append(oxmFields, &oxmField)
566 }
567 return oxmFields
568}
569
570func MkInstructionsFromActions(actions []*ofp.OfpAction) []*ofp.OfpInstruction {
571 instructions := make([]*ofp.OfpInstruction, 0)
572 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
573 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
574 instructions = append(instructions, &instruction)
575 return instructions
576}
577
578// Convenience function to generare ofp_flow_mod message with OXM BASIC match composed from the match_fields, and
579// single APPLY_ACTIONS instruction with a list if ofp_action objects.
580func MkSimpleFlowMod(matchFields []*ofp.OfpOxmField, actions []*ofp.OfpAction, command *ofp.OfpFlowModCommand, kw fu.OfpFlowModArgs) *ofp.OfpFlowMod {
581
582 // Process actions instructions
583 instructions := make([]*ofp.OfpInstruction, 0)
584 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
585 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
586 instructions = append(instructions, &instruction)
587
588 // Process next table
589 if tableId := GetNextTableId(kw); tableId != nil {
590 var instGotoTable ofp.OfpInstruction_GotoTable
591 instGotoTable.GotoTable = &ofp.OfpInstructionGotoTable{TableId: *tableId}
592 inst := ofp.OfpInstruction{Type: uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE), Data: &instGotoTable}
593 instructions = append(instructions, &inst)
594 }
595
596 // Process match fields
597 oxmFields := make([]*ofp.OfpOxmField, 0)
598 for _, matchField := range matchFields {
599 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
600 oxmFields = append(oxmFields, &oxmField)
601 }
602 var match ofp.OfpMatch
603 match.Type = ofp.OfpMatchType_OFPMT_OXM
604 match.OxmFields = oxmFields
605
606 // Create ofp_flow_message
607 msg := &ofp.OfpFlowMod{}
608 if command == nil {
609 msg.Command = ofp.OfpFlowModCommand_OFPFC_ADD
610 } else {
611 msg.Command = *command
612 }
613 msg.Instructions = instructions
614 msg.Match = &match
615
616 // Set the variadic argument values
617 msg = setVariadicModAttributes(msg, kw)
618
619 return msg
620}
621
622func MkMulticastGroupMod(groupId uint32, buckets []*ofp.OfpBucket, command *ofp.OfpGroupModCommand) *ofp.OfpGroupMod {
623 group := &ofp.OfpGroupMod{}
624 if command == nil {
625 group.Command = ofp.OfpGroupModCommand_OFPGC_ADD
626 } else {
627 group.Command = *command
628 }
629 group.Type = ofp.OfpGroupType_OFPGT_ALL
630 group.GroupId = groupId
631 group.Buckets = buckets
632 return group
633}
634
635//SetVariadicModAttributes sets only uint64 or uint32 fields of the ofp_flow_mod message
636func setVariadicModAttributes(mod *ofp.OfpFlowMod, args fu.OfpFlowModArgs) *ofp.OfpFlowMod {
637 if args == nil {
638 return mod
639 }
640 for key, val := range args {
641 switch key {
642 case "cookie":
643 mod.Cookie = val
644 case "cookie_mask":
645 mod.CookieMask = val
646 case "table_id":
647 mod.TableId = uint32(val)
648 case "idle_timeout":
649 mod.IdleTimeout = uint32(val)
650 case "hard_timeout":
651 mod.HardTimeout = uint32(val)
652 case "priority":
653 mod.Priority = uint32(val)
654 case "buffer_id":
655 mod.BufferId = uint32(val)
656 case "out_port":
657 mod.OutPort = uint32(val)
658 case "out_group":
659 mod.OutGroup = uint32(val)
660 case "flags":
661 mod.Flags = uint32(val)
662 }
663 }
664 return mod
665}
666
667// MkFlowStat is a helper method to build flows
668func MkFlowStat(fa *fu.FlowArgs) *ofp.OfpFlowStats {
669 //Build the matchfields
670 matchFields := make([]*ofp.OfpOxmField, 0)
671 for _, val := range fa.MatchFields {
672 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
673 }
674 return FlowStatsEntryFromFlowModMessage(MkSimpleFlowMod(matchFields, fa.Actions, fa.Command, fa.KV))
675}
676
khenaidood20a5852018-10-22 22:09:55 -0400677func MkGroupStat(ga *fu.GroupArgs) *ofp.OfpGroupEntry {
678 return GroupEntryFromGroupMod(MkMulticastGroupMod(ga.GroupId, ga.Buckets, ga.Command))
khenaidoo89b0e942018-10-21 21:11:33 -0400679}
680
681type FlowDecomposer struct {
682 deviceMgr coreIf.DeviceManager
683}
684
685func NewFlowDecomposer(deviceMgr coreIf.DeviceManager) *FlowDecomposer {
686 var decomposer FlowDecomposer
687 decomposer.deviceMgr = deviceMgr
688 return &decomposer
689}
690
691//DecomposeRules decomposes per-device flows and flow-groups from the flows and groups defined on a logical device
692func (fd *FlowDecomposer) DecomposeRules(agent coreIf.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups) *fu.DeviceRules {
693 rules := agent.GetAllDefaultRules()
694 deviceRules := rules.Copy()
695
696 groupMap := make(map[uint32]*ofp.OfpGroupEntry)
697 for _, groupEntry := range groups.Items {
698 groupMap[groupEntry.Desc.GroupId] = groupEntry
699 }
700
701 var decomposedRules *fu.DeviceRules
702 for _, flow := range flows.Items {
703 decomposedRules = fd.decomposeFlow(agent, flow, groupMap)
704 for deviceId, flowAndGroups := range decomposedRules.Rules {
khenaidood20a5852018-10-22 22:09:55 -0400705 deviceRules.CreateEntryIfNotExist(deviceId)
khenaidoo89b0e942018-10-21 21:11:33 -0400706 deviceRules.Rules[deviceId].AddFrom(flowAndGroups)
707 }
708 }
709 return deviceRules
710}
711
khenaidood20a5852018-10-22 22:09:55 -0400712//processControllerBoundFlow decomposes trap flows
713func (fd *FlowDecomposer) processControllerBoundFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
714 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
715
khenaidoo89b0e942018-10-21 21:11:33 -0400716 log.Debugw("trap-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "flow": flow})
khenaidood20a5852018-10-22 22:09:55 -0400717 deviceRules := fu.NewDeviceRules()
718
719 egressHop := route[1]
720
khenaidoo89b0e942018-10-21 21:11:33 -0400721 fg := fu.NewFlowsAndGroups()
722 if agent.GetDeviceGraph().IsRootPort(inPortNo) {
723 log.Debug("trap-nni")
724 var fa *fu.FlowArgs
725 fa = &fu.FlowArgs{
726 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
727 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400728 InPort(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400729 },
730 Actions: GetActions(flow),
731 }
732 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400733 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400734 fg.AddFlow(MkFlowStat(fa))
735 } else {
736 // Trap flow for UNI port
737 log.Debug("trap-uni")
738
739 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
740 var inPorts []uint32
741 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400742 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400743 } else {
744 inPorts = []uint32{inPortNo}
745 }
746 for _, inputPort := range inPorts {
747 var fa *fu.FlowArgs
748 // Upstream flow
749 fa = &fu.FlowArgs{
750 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
751 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400752 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400753 VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | inputPort),
754 },
755 Actions: []*ofp.OfpAction{
756 PushVlan(0x8100),
757 SetField(VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
khenaidood20a5852018-10-22 22:09:55 -0400758 Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400759 },
760 }
761 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400762 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT, VLAN_VID)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400763 fg.AddFlow(MkFlowStat(fa))
764
765 // Downstream flow
766 fa = &fu.FlowArgs{
767 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority)},
768 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400769 InPort(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400770 VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000),
771 VlanPcp(0),
772 Metadata_ofp(uint64(inputPort)),
773 },
774 Actions: []*ofp.OfpAction{
775 PopVlan(),
khenaidood20a5852018-10-22 22:09:55 -0400776 Output(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400777 },
778 }
779 fg.AddFlow(MkFlowStat(fa))
780 }
781 }
khenaidood20a5852018-10-22 22:09:55 -0400782 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400783 return deviceRules
784}
785
786// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
787// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
788// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
789// applied at the OLT
khenaidood20a5852018-10-22 22:09:55 -0400790func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreIf.LogicalDeviceAgent,
791 route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
792
khenaidoo89b0e942018-10-21 21:11:33 -0400793 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400794 deviceRules := fu.NewDeviceRules()
795
796 ingressHop := route[0]
797 egressHop := route[1]
798
khenaidoo89b0e942018-10-21 21:11:33 -0400799 if HasNextTable(flow) {
800 log.Debugw("has-next-table", log.Fields{"table_id": flow.TableId})
801 if outPortNo != 0 {
802 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
803 }
804 var fa *fu.FlowArgs
805 fa = &fu.FlowArgs{
806 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
807 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400808 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400809 },
810 Actions: GetActions(flow),
811 }
812 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400813 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
814
815 // Augment the Actions
816 fa.Actions = append(fa.Actions, Output(ingressHop.Egress))
817
khenaidoo89b0e942018-10-21 21:11:33 -0400818 fg := fu.NewFlowsAndGroups()
819 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400820 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400821 } else {
822 var actions []ofp.OfpActionType
823 var isOutputTypeInActions bool
824 for _, action := range GetActions(flow) {
825 actions = append(actions, action.Type)
826 if !isOutputTypeInActions && action.Type == OUTPUT {
827 isOutputTypeInActions = true
828 }
829 }
830 if len(actions) == 1 && isOutputTypeInActions {
831 var fa *fu.FlowArgs
832 // child device flow
833 fa = &fu.FlowArgs{
834 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
835 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400836 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400837 },
838 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -0400839 Output(ingressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400840 },
841 }
842 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400843 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400844 fg := fu.NewFlowsAndGroups()
845 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400846 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400847
848 // parent device flow
849 fa = &fu.FlowArgs{
850 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
851 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400852 InPort(egressHop.Ingress), //egress_hop.ingress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400853 },
854 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -0400855 Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400856 },
857 }
858 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400859 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400860 fg = fu.NewFlowsAndGroups()
861 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400862 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400863 } else {
864 if outPortNo == 0 {
865 log.Warnw("outPort-should-be-specified", log.Fields{"outPortNo": outPortNo})
866 }
867 var fa *fu.FlowArgs
868 fa = &fu.FlowArgs{
869 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
870 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400871 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400872 },
873 }
874 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400875 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
876
877 //Augment the actions
878 filteredAction := GetActions(flow, OUTPUT)
879 filteredAction = append(filteredAction, Output(egressHop.Egress))
880 fa.Actions = filteredAction
881
khenaidoo89b0e942018-10-21 21:11:33 -0400882 fg := fu.NewFlowsAndGroups()
883 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -0400884 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400885 }
886 }
887 return deviceRules
888}
889
khenaidood20a5852018-10-22 22:09:55 -0400890// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
891func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
892 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
893
khenaidoo89b0e942018-10-21 21:11:33 -0400894 log.Debugw("downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400895 deviceRules := fu.NewDeviceRules()
896
khenaidoo89b0e942018-10-21 21:11:33 -0400897 if outPortNo != 0 {
898 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
899 }
900 ingressHop := route[0]
khenaidood20a5852018-10-22 22:09:55 -0400901 egressHop := route[1]
902
khenaidoo89b0e942018-10-21 21:11:33 -0400903 if GetMetaData(flow) != 0 {
904 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
905 portNumber := uint32(GetPortNumberFromMetadata(flow))
906 if portNumber != 0 {
907 recalculatedRoute := agent.GetRoute(&inPortNo, &portNumber)
908 switch len(recalculatedRoute) {
909 case 0:
910 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": GetMetaData64Bit(flow)})
911 // TODO: Delete flow
912 return deviceRules
913 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400914 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400915 break
916 default:
917 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
918 return deviceRules
919 }
920 ingressHop = recalculatedRoute[0]
921 }
922 innerTag := GetInnerTagFromMetaData(flow)
923 if innerTag == 0 {
924 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": GetMetaData64Bit(flow)})
925 // TODO: Delete flow
926 return deviceRules
927 }
928 var fa *fu.FlowArgs
929 fa = &fu.FlowArgs{
930 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
931 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400932 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400933 Metadata_ofp(innerTag),
934 },
935 Actions: GetActions(flow),
936 }
937 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400938 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT, METADATA)...)
939
940 // Augment the Actions
khenaidoo89b0e942018-10-21 21:11:33 -0400941 fa.Actions = append(fa.Actions, Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400942
khenaidoo89b0e942018-10-21 21:11:33 -0400943 fg := fu.NewFlowsAndGroups()
944 fg.AddFlow(MkFlowStat(fa))
945 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
946 } else { // Create standard flow
947 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
948 var fa *fu.FlowArgs
949 fa = &fu.FlowArgs{
950 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
951 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400952 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400953 },
954 Actions: GetActions(flow),
955 }
956 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -0400957 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
958
959 // Augment the Actions
khenaidoo89b0e942018-10-21 21:11:33 -0400960 fa.Actions = append(fa.Actions, Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400961
khenaidoo89b0e942018-10-21 21:11:33 -0400962 fg := fu.NewFlowsAndGroups()
963 fg.AddFlow(MkFlowStat(fa))
964 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
965 }
966 return deviceRules
967}
968
khenaidood20a5852018-10-22 22:09:55 -0400969// processUnicastFlow decomposes unicast flows
970func (fd *FlowDecomposer) processUnicastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
971 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules {
972
khenaidoo89b0e942018-10-21 21:11:33 -0400973 log.Debugw("unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400974 deviceRules := fu.NewDeviceRules()
975
976 ingressHop := route[0]
977 egressHop := route[1]
978
khenaidoo89b0e942018-10-21 21:11:33 -0400979 var actions []ofp.OfpActionType
980 var isOutputTypeInActions bool
981 for _, action := range GetActions(flow) {
982 actions = append(actions, action.Type)
983 if !isOutputTypeInActions && action.Type == OUTPUT {
984 isOutputTypeInActions = true
985 }
986 }
987 if len(actions) == 1 && isOutputTypeInActions {
988 var fa *fu.FlowArgs
989 // Parent device flow
990 fa = &fu.FlowArgs{
991 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
992 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -0400993 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -0400994 },
995 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -0400996 Output(ingressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400997 },
998 }
999 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001000 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1001
khenaidoo89b0e942018-10-21 21:11:33 -04001002 fg := fu.NewFlowsAndGroups()
1003 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001004 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001005
1006 // Child device flow
1007 fa = &fu.FlowArgs{
1008 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1009 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001010 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001011 },
1012 Actions: []*ofp.OfpAction{
khenaidood20a5852018-10-22 22:09:55 -04001013 Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -04001014 },
1015 }
1016 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001017 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1018
khenaidoo89b0e942018-10-21 21:11:33 -04001019 fg = fu.NewFlowsAndGroups()
1020 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001021 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001022 } else {
1023 var fa *fu.FlowArgs
1024 fa = &fu.FlowArgs{
1025 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1026 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001027 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001028 },
1029 }
1030 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001031 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1032
khenaidoo89b0e942018-10-21 21:11:33 -04001033 // Augment the Actions
khenaidood20a5852018-10-22 22:09:55 -04001034 filteredAction := GetActions(flow, OUTPUT)
1035 filteredAction = append(filteredAction, Output(egressHop.Egress))
1036 fa.Actions = filteredAction
1037
khenaidoo89b0e942018-10-21 21:11:33 -04001038 fg := fu.NewFlowsAndGroups()
1039 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001040 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001041 }
1042 return deviceRules
1043}
1044
khenaidood20a5852018-10-22 22:09:55 -04001045// processMulticastFlow decompose multicast flows
1046func (fd *FlowDecomposer) processMulticastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop,
1047 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpId uint32,
1048 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
1049
khenaidoo89b0e942018-10-21 21:11:33 -04001050 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -04001051 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -04001052
1053 //having no Group yet is the same as having a Group with no buckets
1054 var grp *ofp.OfpGroupEntry
1055 var ok bool
1056 if grp, ok = groupMap[grpId]; !ok {
1057 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpId, "groupMap": groupMap})
1058 return deviceRules
1059 }
1060 if grp == nil || grp.Desc == nil {
1061 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpId, "grp": grp})
1062 return deviceRules
1063 }
1064 for _, bucket := range grp.Desc.Buckets {
1065 otherActions := make([]*ofp.OfpAction, 0)
1066 for _, action := range bucket.Actions {
1067 if action.Type == OUTPUT {
1068 outPortNo = action.GetOutput().Port
1069 } else if action.Type != POP_VLAN {
1070 otherActions = append(otherActions, action)
1071 }
1072 }
1073
1074 route2 := agent.GetRoute(&inPortNo, &outPortNo)
1075 switch len(route2) {
1076 case 0:
1077 log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"})
1078 // TODO: Delete flow
1079 return deviceRules
1080 case 2:
khenaidood20a5852018-10-22 22:09:55 -04001081 log.Debugw("route-found", log.Fields{"ingressHop": route2[0], "egressHop": route2[1]})
khenaidoo89b0e942018-10-21 21:11:33 -04001082 break
1083 default:
1084 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
1085 return deviceRules
1086 }
1087
khenaidood20a5852018-10-22 22:09:55 -04001088 ingressHop := route[0]
1089 ingressHop2 := route2[0]
1090 egressHop := route2[1]
1091
1092 if ingressHop.Ingress != ingressHop2.Ingress {
khenaidoo89b0e942018-10-21 21:11:33 -04001093 log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"})
1094 return deviceRules
1095 }
1096 // Set the parent device flow
1097 var fa *fu.FlowArgs
1098 fa = &fu.FlowArgs{
1099 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1100 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001101 InPort(ingressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001102 },
1103 }
1104 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001105 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT)...)
1106
khenaidoo89b0e942018-10-21 21:11:33 -04001107 // Augment the Actions
khenaidood20a5852018-10-22 22:09:55 -04001108 filteredAction := GetActions(flow, GROUP)
1109 filteredAction = append(filteredAction, PopVlan())
1110 filteredAction = append(filteredAction, Output(route2[1].Ingress))
1111 fa.Actions = filteredAction
1112
khenaidoo89b0e942018-10-21 21:11:33 -04001113 fg := fu.NewFlowsAndGroups()
1114 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001115 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001116
1117 // Set the child device flow
1118 fa = &fu.FlowArgs{
1119 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
1120 MatchFields: []*ofp.OfpOxmOfbField{
khenaidood20a5852018-10-22 22:09:55 -04001121 InPort(egressHop.Ingress),
khenaidoo89b0e942018-10-21 21:11:33 -04001122 },
1123 }
1124 // Augment the matchfields with the ofpfields from the flow
khenaidood20a5852018-10-22 22:09:55 -04001125 fa.MatchFields = append(fa.MatchFields, GetOfbFields(flow, IN_PORT, VLAN_VID, VLAN_PCP)...)
1126
khenaidoo89b0e942018-10-21 21:11:33 -04001127 // Augment the Actions
khenaidood20a5852018-10-22 22:09:55 -04001128 otherActions = append(otherActions, Output(egressHop.Egress))
khenaidoo89b0e942018-10-21 21:11:33 -04001129 fa.Actions = otherActions
khenaidood20a5852018-10-22 22:09:55 -04001130
khenaidoo89b0e942018-10-21 21:11:33 -04001131 fg = fu.NewFlowsAndGroups()
1132 fg.AddFlow(MkFlowStat(fa))
khenaidood20a5852018-10-22 22:09:55 -04001133 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -04001134 }
1135 return deviceRules
1136}
1137
khenaidood20a5852018-10-22 22:09:55 -04001138// decomposeFlow decomposes a flow for a logical device into flows for each physical device
1139func (fd *FlowDecomposer) decomposeFlow(agent coreIf.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
1140 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
1141
khenaidoo89b0e942018-10-21 21:11:33 -04001142 inPortNo := GetInPort(flow)
1143 outPortNo := GetOutPort(flow)
1144
1145 deviceRules := fu.NewDeviceRules()
1146
1147 route := agent.GetRoute(&inPortNo, &outPortNo)
1148 switch len(route) {
1149 case 0:
1150 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"})
1151 // TODO: Delete flow
1152 return deviceRules
1153 case 2:
1154 log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]})
1155 break
1156 default:
1157 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)})
1158 return deviceRules
1159 }
1160
1161 var ingressDevice *voltha.Device
khenaidoo89b0e942018-10-21 21:11:33 -04001162 var err error
1163 if ingressDevice, err = fd.deviceMgr.GetDevice(route[0].DeviceID); err != nil {
1164 log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID})
1165 return deviceRules
1166 }
khenaidoo89b0e942018-10-21 21:11:33 -04001167
1168 isDownstream := ingressDevice.Root
1169 isUpstream := !isDownstream
1170
1171 // Process controller bound flow
1172 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
khenaidood20a5852018-10-22 22:09:55 -04001173 deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001174 } else {
1175 if isUpstream {
khenaidood20a5852018-10-22 22:09:55 -04001176 deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001177 } else if HasNextTable(flow) {
khenaidood20a5852018-10-22 22:09:55 -04001178 deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001179 } else if outPortNo != 0 { // Unicast
khenaidood20a5852018-10-22 22:09:55 -04001180 deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow)
khenaidoo89b0e942018-10-21 21:11:33 -04001181 } else if grpId := GetGroup(flow); grpId != 0 { //Multicast
khenaidood20a5852018-10-22 22:09:55 -04001182 deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, grpId, groupMap)
khenaidoo89b0e942018-10-21 21:11:33 -04001183 }
1184 }
1185 return deviceRules
1186}