blob: 76794e37c813e2c28f152056cadb0ab4fc5cad8f [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
npujar1d86a522019-11-14 17:11:16 +053017package flowdecomposition
khenaidoo89b0e942018-10-21 21:11:33 -040018
19import (
npujar467fe752020-01-16 20:17:45 +053020 "context"
khenaidoo19d7b632018-10-30 10:49:50 -040021 "github.com/gogo/protobuf/proto"
npujar1d86a522019-11-14 17:11:16 +053022 "github.com/opencord/voltha-go/rw_core/coreif"
khenaidoo820197c2020-02-13 16:35:33 -050023 "github.com/opencord/voltha-go/rw_core/route"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080024 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
25 "github.com/opencord/voltha-lib-go/v3/pkg/log"
26 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
27 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoo820197c2020-02-13 16:35:33 -050028 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
khenaidoo89b0e942018-10-21 21:11:33 -040030)
31
32func init() {
npujar1d86a522019-11-14 17:11:16 +053033 _, err := log.AddPackage(log.JSON, log.DebugLevel, nil)
34 if err != nil {
35 log.Errorw("unable-to-register-package-to-the-log-map", log.Fields{"error": err})
36 }
khenaidoo89b0e942018-10-21 21:11:33 -040037}
38
npujar1d86a522019-11-14 17:11:16 +053039// FlowDecomposer represent flow decomposer attribute
khenaidoo89b0e942018-10-21 21:11:33 -040040type FlowDecomposer struct {
npujar1d86a522019-11-14 17:11:16 +053041 deviceMgr coreif.DeviceManager
khenaidoo89b0e942018-10-21 21:11:33 -040042}
43
npujar1d86a522019-11-14 17:11:16 +053044// NewFlowDecomposer creates flow decomposer instance
45func NewFlowDecomposer(deviceMgr coreif.DeviceManager) *FlowDecomposer {
khenaidoo89b0e942018-10-21 21:11:33 -040046 var decomposer FlowDecomposer
47 decomposer.deviceMgr = deviceMgr
48 return &decomposer
49}
50
51//DecomposeRules decomposes per-device flows and flow-groups from the flows and groups defined on a logical device
khenaidoo820197c2020-02-13 16:35:33 -050052func (fd *FlowDecomposer) DecomposeRules(ctx context.Context, agent coreif.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups) (*fu.DeviceRules, error) {
khenaidoo3306c992019-05-24 16:57:35 -040053 deviceRules := *fu.NewDeviceRules()
khenaidoo2c6a0992019-04-29 13:46:56 -040054 devicesToUpdate := make(map[string]string)
khenaidoo89b0e942018-10-21 21:11:33 -040055
56 groupMap := make(map[uint32]*ofp.OfpGroupEntry)
57 for _, groupEntry := range groups.Items {
58 groupMap[groupEntry.Desc.GroupId] = groupEntry
59 }
60
khenaidoo89b0e942018-10-21 21:11:33 -040061 for _, flow := range flows.Items {
khenaidoo820197c2020-02-13 16:35:33 -050062 decomposedRules, err := fd.decomposeFlow(ctx, agent, flow, groupMap)
63 if err != nil {
64 return nil, err
65 }
npujar1d86a522019-11-14 17:11:16 +053066 for deviceID, flowAndGroups := range decomposedRules.Rules {
67 deviceRules.CreateEntryIfNotExist(deviceID)
68 deviceRules.Rules[deviceID].AddFrom(flowAndGroups)
69 devicesToUpdate[deviceID] = deviceID
khenaidoo89b0e942018-10-21 21:11:33 -040070 }
71 }
khenaidoo820197c2020-02-13 16:35:33 -050072 return deviceRules.FilterRules(devicesToUpdate), nil
khenaidoo89b0e942018-10-21 21:11:33 -040073}
74
khenaidoo19d7b632018-10-30 10:49:50 -040075// Handles special case of any controller-bound flow for a parent device
76func (fd *FlowDecomposer) updateOutputPortForControllerBoundFlowForParentDevide(flow *ofp.OfpFlowStats,
Scott Bakerfdea1e32020-02-21 15:35:41 -080077 dr *fu.DeviceRules) (*fu.DeviceRules, error) {
khenaidoo68c930b2019-05-13 11:46:51 -040078 EAPOL := fu.EthType(0x888e)
79 IGMP := fu.IpProto(2)
80 UDP := fu.IpProto(17)
khenaidoo19d7b632018-10-30 10:49:50 -040081
82 newDeviceRules := dr.Copy()
83 // Check whether we are dealing with a parent device
npujar1d86a522019-11-14 17:11:16 +053084 for deviceID, fg := range dr.GetRules() {
85 if root, _ := fd.deviceMgr.IsRootDevice(deviceID); root {
86 newDeviceRules.ClearFlows(deviceID)
khenaidoo19d7b632018-10-30 10:49:50 -040087 for i := 0; i < fg.Flows.Len(); i++ {
88 f := fg.GetFlow(i)
89 UpdateOutPortNo := false
khenaidoo68c930b2019-05-13 11:46:51 -040090 for _, field := range fu.GetOfbFields(f) {
khenaidoo19d7b632018-10-30 10:49:50 -040091 UpdateOutPortNo = (field.String() == EAPOL.String())
92 UpdateOutPortNo = UpdateOutPortNo || (field.String() == IGMP.String())
93 UpdateOutPortNo = UpdateOutPortNo || (field.String() == UDP.String())
94 if UpdateOutPortNo {
95 break
96 }
97 }
98 if UpdateOutPortNo {
khenaidoo68c930b2019-05-13 11:46:51 -040099 f = fu.UpdateOutputPortByActionType(f, uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS),
khenaidoo19d7b632018-10-30 10:49:50 -0400100 uint32(ofp.OfpPortNo_OFPP_CONTROLLER))
101 }
102 // Update flow Id as a change in the instruction field will result in a new flow ID
Scott Bakerfdea1e32020-02-21 15:35:41 -0800103 var err error
104 if f.Id, err = fu.HashFlowStats(f); err != nil {
105 return nil, err
106 }
npujar1d86a522019-11-14 17:11:16 +0530107 newDeviceRules.AddFlow(deviceID, (proto.Clone(f)).(*ofp.OfpFlowStats))
khenaidoo19d7b632018-10-30 10:49:50 -0400108 }
109 }
110 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400111
Scott Bakerfdea1e32020-02-21 15:35:41 -0800112 return newDeviceRules, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400113}
114
khenaidood20a5852018-10-22 22:09:55 -0400115//processControllerBoundFlow decomposes trap flows
khenaidoo820197c2020-02-13 16:35:33 -0500116func (fd *FlowDecomposer) processControllerBoundFlow(ctx context.Context, agent coreif.LogicalDeviceAgent, path []route.Hop,
Scott Bakerfdea1e32020-02-21 15:35:41 -0800117 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400118
khenaidoo89b0e942018-10-21 21:11:33 -0400119 log.Debugw("trap-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "flow": flow})
khenaidood20a5852018-10-22 22:09:55 -0400120 deviceRules := fu.NewDeviceRules()
npujar1d86a522019-11-14 17:11:16 +0530121 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400122 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400123
khenaidoo820197c2020-02-13 16:35:33 -0500124 ingressHop := path[0]
125 egressHop := path[1]
khenaidood20a5852018-10-22 22:09:55 -0400126
Humera Kouser4ff89012019-08-25 19:01:51 -0400127 //case of packet_in from NNI port rule
khenaidoo820197c2020-02-13 16:35:33 -0500128 if agent.GetDeviceRoutes().IsRootPort(inPortNo) {
Humera Kouser4ff89012019-08-25 19:01:51 -0400129 // Trap flow for NNI port
khenaidoo89b0e942018-10-21 21:11:33 -0400130 log.Debug("trap-nni")
Humera Kouser4ff89012019-08-25 19:01:51 -0400131
npujar1d86a522019-11-14 17:11:16 +0530132 fa := &fu.FlowArgs{
Humera Kouser4ff89012019-08-25 19:01:51 -0400133 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie},
134 MatchFields: []*ofp.OfpOxmOfbField{
135 fu.InPort(egressHop.Egress),
136 },
137 Actions: fu.GetActions(flow),
138 }
139 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400140 fg := fu.NewFlowsAndGroups()
Humera Kouser4ff89012019-08-25 19:01:51 -0400141 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
Scott Bakerfdea1e32020-02-21 15:35:41 -0800142 fs, err := fu.MkFlowStat(fa)
143 if err != nil {
144 return nil, err
145 }
146 fg.AddFlow(fs)
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400147 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400148 } else {
149 // Trap flow for UNI port
150 log.Debug("trap-uni")
151
Matt Jeannerete75f2842020-03-14 15:45:12 -0400152 //inPortNo is 0 for wildcard input case, do not include upstream port for controller bound flow in input
khenaidoo89b0e942018-10-21 21:11:33 -0400153 var inPorts []uint32
154 if inPortNo == 0 {
khenaidood20a5852018-10-22 22:09:55 -0400155 inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no
khenaidoo89b0e942018-10-21 21:11:33 -0400156 } else {
157 inPorts = []uint32{inPortNo}
158 }
159 for _, inputPort := range inPorts {
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400160 // Upstream flow on parent (olt) device
npujar1d86a522019-11-14 17:11:16 +0530161 faParent := &fu.FlowArgs{
162 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400163 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400164 fu.InPort(egressHop.Ingress),
khenaidoo68c930b2019-05-13 11:46:51 -0400165 fu.TunnelId(uint64(inputPort)),
khenaidoo89b0e942018-10-21 21:11:33 -0400166 },
167 Actions: []*ofp.OfpAction{
khenaidoo68c930b2019-05-13 11:46:51 -0400168 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400169 },
170 }
171 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400172 faParent.MatchFields = append(faParent.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
173 fgParent := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800174 fs, err := fu.MkFlowStat(faParent)
175 if err != nil {
176 return nil, err
177 }
178 fgParent.AddFlow(fs)
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400179 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fgParent)
180 log.Debugw("parent-trap-flow-set", log.Fields{"flow": faParent})
181
182 // Upstream flow on child (onu) device
183 var actions []*ofp.OfpAction
184 setvid := fu.GetVlanVid(flow)
185 if setvid != nil {
186 // have this child push the vlan the parent is matching/trapping on above
187 actions = []*ofp.OfpAction{
188 fu.PushVlan(0x8100),
189 fu.SetField(fu.VlanVid(*setvid)),
190 fu.Output(ingressHop.Egress),
191 }
192 } else {
193 // otherwise just set the egress port
194 actions = []*ofp.OfpAction{
195 fu.Output(ingressHop.Egress),
196 }
197 }
npujar1d86a522019-11-14 17:11:16 +0530198 faChild := &fu.FlowArgs{
199 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400200 MatchFields: []*ofp.OfpOxmOfbField{
201 fu.InPort(ingressHop.Ingress),
202 fu.TunnelId(uint64(inputPort)),
203 },
204 Actions: actions,
205 }
206 // Augment the matchfields with the ofpfields from the flow.
207 // If the parent has a match vid and the child is setting that match vid exclude the the match vlan
208 // for the child given it will be setting that vlan and the parent will be matching on it
209 if setvid != nil {
210 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID)...)
211 } else {
212 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
213 }
214 fgChild := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800215 fs, err = fu.MkFlowStat(faChild)
216 if err != nil {
217 return nil, err
218 }
219 fgChild.AddFlow(fs)
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400220 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fgChild)
221 log.Debugw("child-trap-flow-set", log.Fields{"flow": faChild})
khenaidoo89b0e942018-10-21 21:11:33 -0400222 }
223 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400224
Scott Bakerfdea1e32020-02-21 15:35:41 -0800225 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400226}
227
228// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
229// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
230// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
231// applied at the OLT
khenaidoo820197c2020-02-13 16:35:33 -0500232func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(ctx context.Context,
Scott Bakerfdea1e32020-02-21 15:35:41 -0800233 path []route.Hop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400234
khenaidoo89b0e942018-10-21 21:11:33 -0400235 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400236 deviceRules := fu.NewDeviceRules()
237
npujar1d86a522019-11-14 17:11:16 +0530238 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400239 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
240
khenaidoo820197c2020-02-13 16:35:33 -0500241 ingressHop := path[0]
242 egressHop := path[1]
khenaidood20a5852018-10-22 22:09:55 -0400243
Manikkaraj kb1a10922019-07-29 12:10:34 -0400244 if flow.TableId == 0 && fu.HasNextTable(flow) {
245 log.Debugw("decomposing-onu-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
khenaidoo89b0e942018-10-21 21:11:33 -0400246 if outPortNo != 0 {
247 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800248 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400249 }
npujar1d86a522019-11-14 17:11:16 +0530250 fa := &fu.FlowArgs{
251 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400252 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400253 fu.InPort(ingressHop.Ingress),
254 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400255 },
khenaidoo68c930b2019-05-13 11:46:51 -0400256 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400257 }
258 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400259 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400260
261 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400262 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400263
khenaidoo89b0e942018-10-21 21:11:33 -0400264 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800265 fs, err := fu.MkFlowStat(fa)
266 if err != nil {
267 return nil, err
268 }
269 fg.AddFlow(fs)
khenaidood20a5852018-10-22 22:09:55 -0400270 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400271 } else if flow.TableId == 1 && outPortNo != 0 {
272 log.Debugw("decomposing-olt-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
npujar1d86a522019-11-14 17:11:16 +0530273 fa := &fu.FlowArgs{
274 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400275 MatchFields: []*ofp.OfpOxmOfbField{
276 fu.InPort(egressHop.Ingress),
277 fu.TunnelId(uint64(inPortNo)),
278 },
khenaidoo89b0e942018-10-21 21:11:33 -0400279 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400280 // Augment the matchfields with the ofpfields from the flow
281 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400282
Manikkaraj kb1a10922019-07-29 12:10:34 -0400283 //Augment the actions
284 filteredAction := fu.GetActions(flow, fu.OUTPUT)
285 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
286 fa.Actions = filteredAction
khenaidood20a5852018-10-22 22:09:55 -0400287
Manikkaraj kb1a10922019-07-29 12:10:34 -0400288 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800289 fs, err := fu.MkFlowStat(fa)
290 if err != nil {
291 return nil, err
292 }
293 fg.AddFlow(fs)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400294 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400295 }
Scott Bakerfdea1e32020-02-21 15:35:41 -0800296 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400297}
298
khenaidood20a5852018-10-22 22:09:55 -0400299// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
khenaidoo820197c2020-02-13 16:35:33 -0500300func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(ctx context.Context, agent coreif.LogicalDeviceAgent, path []route.Hop,
Scott Bakerfdea1e32020-02-21 15:35:41 -0800301 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) (*fu.DeviceRules, error) {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400302 log.Debugw("decomposing-olt-flow-in-downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400303 deviceRules := fu.NewDeviceRules()
npujar1d86a522019-11-14 17:11:16 +0530304 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400305 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400306
khenaidoo89b0e942018-10-21 21:11:33 -0400307 if outPortNo != 0 {
308 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800309 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400310 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400311
312 if flow.TableId != 0 {
313 log.Warnw("This is not olt pipeline table, so skipping", log.Fields{"tableId": flow.TableId})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800314 return deviceRules, nil
Manikkaraj kb1a10922019-07-29 12:10:34 -0400315 }
316
khenaidoo820197c2020-02-13 16:35:33 -0500317 ingressHop := path[0]
318 egressHop := path[1]
Manikkaraj kb1a10922019-07-29 12:10:34 -0400319 if metadataFromwriteMetadata != 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400320 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400321 portNumber := fu.GetEgressPortNumberFromWriteMetadata(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400322 if portNumber != 0 {
khenaidoo820197c2020-02-13 16:35:33 -0500323 recalculatedRoute, err := agent.GetRoute(ctx, inPortNo, portNumber)
324 if err != nil {
325 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "metadata": metadataFromwriteMetadata, "error": err})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800326 return deviceRules, nil
khenaidoo820197c2020-02-13 16:35:33 -0500327 }
khenaidoo89b0e942018-10-21 21:11:33 -0400328 switch len(recalculatedRoute) {
329 case 0:
Manikkaraj kb1a10922019-07-29 12:10:34 -0400330 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
331 //TODO: Delete flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800332 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400333 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400334 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400335 default:
khenaidoo820197c2020-02-13 16:35:33 -0500336 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(path)})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800337 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400338 }
339 ingressHop = recalculatedRoute[0]
340 }
khenaidoo68c930b2019-05-13 11:46:51 -0400341 innerTag := fu.GetInnerTagFromMetaData(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400342 if innerTag == 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400343 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
344 //TODO: Delete flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800345 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400346 }
npujar1d86a522019-11-14 17:11:16 +0530347 fa := &fu.FlowArgs{
348 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400349 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400350 fu.InPort(ingressHop.Ingress),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400351 fu.Metadata_ofp(uint64(innerTag)),
khenaidoo68c930b2019-05-13 11:46:51 -0400352 fu.TunnelId(uint64(portNumber)),
khenaidoo89b0e942018-10-21 21:11:33 -0400353 },
khenaidoo68c930b2019-05-13 11:46:51 -0400354 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400355 }
356 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400357 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...)
khenaidood20a5852018-10-22 22:09:55 -0400358
359 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400360 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400361
khenaidoo89b0e942018-10-21 21:11:33 -0400362 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800363 fs, err := fu.MkFlowStat(fa)
364 if err != nil {
365 return nil, err
366 }
367 fg.AddFlow(fs)
khenaidoo89b0e942018-10-21 21:11:33 -0400368 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
369 } else { // Create standard flow
370 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
npujar1d86a522019-11-14 17:11:16 +0530371 fa := &fu.FlowArgs{
372 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400373 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400374 fu.InPort(ingressHop.Ingress),
375 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400376 },
khenaidoo68c930b2019-05-13 11:46:51 -0400377 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400378 }
379 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400380 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400381
382 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400383 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400384
khenaidoo89b0e942018-10-21 21:11:33 -0400385 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800386 fs, err := fu.MkFlowStat(fa)
387 if err != nil {
388 return nil, err
389 }
390 fg.AddFlow(fs)
khenaidoo89b0e942018-10-21 21:11:33 -0400391 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
392 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400393
Scott Bakerfdea1e32020-02-21 15:35:41 -0800394 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400395}
396
khenaidood20a5852018-10-22 22:09:55 -0400397// processUnicastFlow decomposes unicast flows
khenaidoo820197c2020-02-13 16:35:33 -0500398func (fd *FlowDecomposer) processUnicastFlow(ctx context.Context, path []route.Hop,
Scott Bakerfdea1e32020-02-21 15:35:41 -0800399 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400400
Manikkaraj kb1a10922019-07-29 12:10:34 -0400401 log.Debugw("decomposing-onu-flow-in-downstream-unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400402 deviceRules := fu.NewDeviceRules()
403
khenaidoo820197c2020-02-13 16:35:33 -0500404 egressHop := path[1]
khenaidood20a5852018-10-22 22:09:55 -0400405
npujar1d86a522019-11-14 17:11:16 +0530406 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400407 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
npujar1d86a522019-11-14 17:11:16 +0530408 fa := &fu.FlowArgs{
409 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400410 MatchFields: []*ofp.OfpOxmOfbField{
411 fu.InPort(egressHop.Ingress),
412 },
khenaidoo89b0e942018-10-21 21:11:33 -0400413 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400414 // Augment the matchfields with the ofpfields from the flow
415 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400416
Manikkaraj kb1a10922019-07-29 12:10:34 -0400417 // Augment the Actions
418 filteredAction := fu.GetActions(flow, fu.OUTPUT)
419 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
420 fa.Actions = filteredAction
khenaidoo89b0e942018-10-21 21:11:33 -0400421
Manikkaraj kb1a10922019-07-29 12:10:34 -0400422 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800423 fs, err := fu.MkFlowStat(fa)
424 if err != nil {
425 return nil, err
426 }
427 fg.AddFlow(fs)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400428 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
Scott Bakerfdea1e32020-02-21 15:35:41 -0800429 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400430}
431
khenaidood20a5852018-10-22 22:09:55 -0400432// processMulticastFlow decompose multicast flows
khenaidoo820197c2020-02-13 16:35:33 -0500433func (fd *FlowDecomposer) processMulticastFlow(ctx context.Context, path []route.Hop,
npujar1d86a522019-11-14 17:11:16 +0530434 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpID uint32,
khenaidood20a5852018-10-22 22:09:55 -0400435 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
436
khenaidoo89b0e942018-10-21 21:11:33 -0400437 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400438 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -0400439
440 //having no Group yet is the same as having a Group with no buckets
441 var grp *ofp.OfpGroupEntry
442 var ok bool
npujar1d86a522019-11-14 17:11:16 +0530443 if grp, ok = groupMap[grpID]; !ok {
444 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpID, "groupMap": groupMap})
khenaidoo89b0e942018-10-21 21:11:33 -0400445 return deviceRules
446 }
447 if grp == nil || grp.Desc == nil {
npujar1d86a522019-11-14 17:11:16 +0530448 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpID, "grp": grp})
khenaidoo89b0e942018-10-21 21:11:33 -0400449 return deviceRules
450 }
khenaidoo89b0e942018-10-21 21:11:33 -0400451
khenaidoo820197c2020-02-13 16:35:33 -0500452 deviceRules.CreateEntryIfNotExist(path[0].DeviceID)
Esin Karaman09959ae2019-11-29 13:59:58 +0000453 fg := fu.NewFlowsAndGroups()
454 fg.AddFlow(flow)
455 //return the multicast flow without decomposing it
khenaidoo820197c2020-02-13 16:35:33 -0500456 deviceRules.AddFlowsAndGroup(path[0].DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400457 return deviceRules
458}
459
khenaidood20a5852018-10-22 22:09:55 -0400460// decomposeFlow decomposes a flow for a logical device into flows for each physical device
npujar467fe752020-01-16 20:17:45 +0530461func (fd *FlowDecomposer) decomposeFlow(ctx context.Context, agent coreif.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
khenaidoo820197c2020-02-13 16:35:33 -0500462 groupMap map[uint32]*ofp.OfpGroupEntry) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400463
khenaidoo68c930b2019-05-13 11:46:51 -0400464 inPortNo := fu.GetInPort(flow)
Esin Karaman09959ae2019-11-29 13:59:58 +0000465 if fu.HasGroup(flow) && inPortNo == 0 {
466 //if no in-port specified for a multicast flow, put NNI port as in-port
khenaidoo820197c2020-02-13 16:35:33 -0500467 //so that a valid path can be found for the flow
Esin Karaman09959ae2019-11-29 13:59:58 +0000468 nniPorts := agent.GetNNIPorts()
469 if len(nniPorts) > 0 {
470 inPortNo = nniPorts[0]
khenaidoo820197c2020-02-13 16:35:33 -0500471 log.Debugw("assigning-nni-port-as-in-port-for-multicast-flow", log.Fields{"nni": nniPorts[0], "flow:": flow})
Esin Karaman09959ae2019-11-29 13:59:58 +0000472 }
473 }
khenaidoo68c930b2019-05-13 11:46:51 -0400474 outPortNo := fu.GetOutPort(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400475 deviceRules := fu.NewDeviceRules()
khenaidoo820197c2020-02-13 16:35:33 -0500476 path, err := agent.GetRoute(ctx, inPortNo, outPortNo)
477 if err != nil {
478 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "error": err})
479 return deviceRules, err
480 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400481
khenaidoo820197c2020-02-13 16:35:33 -0500482 switch len(path) {
khenaidoo89b0e942018-10-21 21:11:33 -0400483 case 0:
khenaidoo820197c2020-02-13 16:35:33 -0500484 return deviceRules, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400485 case 2:
khenaidoo820197c2020-02-13 16:35:33 -0500486 log.Debugw("route-found", log.Fields{"ingressHop": path[0], "egressHop": path[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400487 default:
khenaidoo820197c2020-02-13 16:35:33 -0500488 return deviceRules, status.Errorf(codes.Aborted, "invalid route length %d", len(path))
khenaidoo89b0e942018-10-21 21:11:33 -0400489 }
490
khenaidoo89b0e942018-10-21 21:11:33 -0400491 // Process controller bound flow
492 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
Scott Bakerfdea1e32020-02-21 15:35:41 -0800493 deviceRules, err = fd.processControllerBoundFlow(ctx, agent, path, inPortNo, outPortNo, flow)
494 if err != nil {
495 return nil, err
496 }
khenaidoo89b0e942018-10-21 21:11:33 -0400497 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500498 var ingressDevice *voltha.Device
499 var err error
khenaidoo820197c2020-02-13 16:35:33 -0500500 if ingressDevice, err = fd.deviceMgr.GetDevice(ctx, path[0].DeviceID); err != nil {
501 return deviceRules, err
khenaidoo297cd252019-02-07 22:10:23 -0500502 }
503 isUpstream := !ingressDevice.Root
Manikkaraj kb1a10922019-07-29 12:10:34 -0400504 if isUpstream { // Unicast OLT and ONU UL
khenaidoo820197c2020-02-13 16:35:33 -0500505 log.Debug("process-olt-nd-onu-upstream-noncontrollerbound-unicast-flows", log.Fields{"flows": flow})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800506 deviceRules, err = fd.processUpstreamNonControllerBoundFlow(ctx, path, inPortNo, outPortNo, flow)
507 if err != nil {
508 return nil, err
509 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400510 } else if fu.HasNextTable(flow) && flow.TableId == 0 { // Unicast OLT flow DL
khenaidoo820197c2020-02-13 16:35:33 -0500511 log.Debugw("process-olt-downstream-noncontrollerbound-flow-with-nexttable", log.Fields{"flows": flow})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800512 deviceRules, err = fd.processDownstreamFlowWithNextTable(ctx, agent, path, inPortNo, outPortNo, flow)
513 if err != nil {
514 return nil, err
515 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400516 } else if flow.TableId == 1 && outPortNo != 0 { // Unicast ONU flow DL
khenaidoo820197c2020-02-13 16:35:33 -0500517 log.Debugw("process-onu-downstream-unicast-flow", log.Fields{"flows": flow})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800518 deviceRules, err = fd.processUnicastFlow(ctx, path, inPortNo, outPortNo, flow)
519 if err != nil {
520 return nil, err
521 }
npujar1d86a522019-11-14 17:11:16 +0530522 } else if grpID := fu.GetGroup(flow); grpID != 0 && flow.TableId == 0 { //Multicast
khenaidoo820197c2020-02-13 16:35:33 -0500523 log.Debugw("process-multicast-flow", log.Fields{"flows": flow})
524 deviceRules = fd.processMulticastFlow(ctx, path, inPortNo, outPortNo, flow, grpID, groupMap)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400525 } else {
khenaidoo820197c2020-02-13 16:35:33 -0500526 return deviceRules, status.Errorf(codes.Aborted, "unknown downstream flow %v", *flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400527 }
528 }
Scott Bakerfdea1e32020-02-21 15:35:41 -0800529 deviceRules, err = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
530 return deviceRules, err
khenaidoo89b0e942018-10-21 21:11:33 -0400531}