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