blob: 16754b9d98309976e32c3e14fa9bd30c8346355c [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
152 //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input
153 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.PushVlan(0x8100),
169 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
170 fu.Output(egressHop.Egress),
khenaidoo89b0e942018-10-21 21:11:33 -0400171 },
172 }
173 // Augment the matchfields with the ofpfields from the flow
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400174 faParent.MatchFields = append(faParent.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
175 fgParent := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800176 fs, err := fu.MkFlowStat(faParent)
177 if err != nil {
178 return nil, err
179 }
180 fgParent.AddFlow(fs)
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400181 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fgParent)
182 log.Debugw("parent-trap-flow-set", log.Fields{"flow": faParent})
183
184 // Upstream flow on child (onu) device
185 var actions []*ofp.OfpAction
186 setvid := fu.GetVlanVid(flow)
187 if setvid != nil {
188 // have this child push the vlan the parent is matching/trapping on above
189 actions = []*ofp.OfpAction{
190 fu.PushVlan(0x8100),
191 fu.SetField(fu.VlanVid(*setvid)),
192 fu.Output(ingressHop.Egress),
193 }
194 } else {
195 // otherwise just set the egress port
196 actions = []*ofp.OfpAction{
197 fu.Output(ingressHop.Egress),
198 }
199 }
npujar1d86a522019-11-14 17:11:16 +0530200 faChild := &fu.FlowArgs{
201 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400202 MatchFields: []*ofp.OfpOxmOfbField{
203 fu.InPort(ingressHop.Ingress),
204 fu.TunnelId(uint64(inputPort)),
205 },
206 Actions: actions,
207 }
208 // Augment the matchfields with the ofpfields from the flow.
209 // If the parent has a match vid and the child is setting that match vid exclude the the match vlan
210 // for the child given it will be setting that vlan and the parent will be matching on it
211 if setvid != nil {
212 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID)...)
213 } else {
214 faChild.MatchFields = append(faChild.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
215 }
216 fgChild := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800217 fs, err = fu.MkFlowStat(faChild)
218 if err != nil {
219 return nil, err
220 }
221 fgChild.AddFlow(fs)
Matt Jeanneretb423bad2019-10-10 20:42:19 -0400222 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fgChild)
223 log.Debugw("child-trap-flow-set", log.Fields{"flow": faChild})
khenaidoo89b0e942018-10-21 21:11:33 -0400224 }
225 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400226
Scott Bakerfdea1e32020-02-21 15:35:41 -0800227 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400228}
229
230// processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is
231// upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the
232// goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is
233// applied at the OLT
khenaidoo820197c2020-02-13 16:35:33 -0500234func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(ctx context.Context,
Scott Bakerfdea1e32020-02-21 15:35:41 -0800235 path []route.Hop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400236
khenaidoo89b0e942018-10-21 21:11:33 -0400237 log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400238 deviceRules := fu.NewDeviceRules()
239
npujar1d86a522019-11-14 17:11:16 +0530240 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400241 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
242
khenaidoo820197c2020-02-13 16:35:33 -0500243 ingressHop := path[0]
244 egressHop := path[1]
khenaidood20a5852018-10-22 22:09:55 -0400245
Manikkaraj kb1a10922019-07-29 12:10:34 -0400246 if flow.TableId == 0 && fu.HasNextTable(flow) {
247 log.Debugw("decomposing-onu-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
khenaidoo89b0e942018-10-21 21:11:33 -0400248 if outPortNo != 0 {
249 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800250 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400251 }
npujar1d86a522019-11-14 17:11:16 +0530252 fa := &fu.FlowArgs{
253 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400254 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400255 fu.InPort(ingressHop.Ingress),
256 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400257 },
khenaidoo68c930b2019-05-13 11:46:51 -0400258 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400259 }
260 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400261 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400262
263 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400264 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400265
khenaidoo89b0e942018-10-21 21:11:33 -0400266 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800267 fs, err := fu.MkFlowStat(fa)
268 if err != nil {
269 return nil, err
270 }
271 fg.AddFlow(fs)
khenaidood20a5852018-10-22 22:09:55 -0400272 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400273 } else if flow.TableId == 1 && outPortNo != 0 {
274 log.Debugw("decomposing-olt-flow-in-upstream-has-next-table", log.Fields{"table_id": flow.TableId})
npujar1d86a522019-11-14 17:11:16 +0530275 fa := &fu.FlowArgs{
276 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400277 MatchFields: []*ofp.OfpOxmOfbField{
278 fu.InPort(egressHop.Ingress),
279 fu.TunnelId(uint64(inPortNo)),
280 },
khenaidoo89b0e942018-10-21 21:11:33 -0400281 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400282 // Augment the matchfields with the ofpfields from the flow
283 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidoo89b0e942018-10-21 21:11:33 -0400284
Manikkaraj kb1a10922019-07-29 12:10:34 -0400285 //Augment the actions
286 filteredAction := fu.GetActions(flow, fu.OUTPUT)
287 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
288 fa.Actions = filteredAction
khenaidood20a5852018-10-22 22:09:55 -0400289
Manikkaraj kb1a10922019-07-29 12:10:34 -0400290 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800291 fs, err := fu.MkFlowStat(fa)
292 if err != nil {
293 return nil, err
294 }
295 fg.AddFlow(fs)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400296 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400297 }
Scott Bakerfdea1e32020-02-21 15:35:41 -0800298 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400299}
300
khenaidood20a5852018-10-22 22:09:55 -0400301// processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions
khenaidoo820197c2020-02-13 16:35:33 -0500302func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(ctx context.Context, agent coreif.LogicalDeviceAgent, path []route.Hop,
Scott Bakerfdea1e32020-02-21 15:35:41 -0800303 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) (*fu.DeviceRules, error) {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400304 log.Debugw("decomposing-olt-flow-in-downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400305 deviceRules := fu.NewDeviceRules()
npujar1d86a522019-11-14 17:11:16 +0530306 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400307 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
khenaidood20a5852018-10-22 22:09:55 -0400308
khenaidoo89b0e942018-10-21 21:11:33 -0400309 if outPortNo != 0 {
310 log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800311 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400312 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400313
314 if flow.TableId != 0 {
315 log.Warnw("This is not olt pipeline table, so skipping", log.Fields{"tableId": flow.TableId})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800316 return deviceRules, nil
Manikkaraj kb1a10922019-07-29 12:10:34 -0400317 }
318
khenaidoo820197c2020-02-13 16:35:33 -0500319 ingressHop := path[0]
320 egressHop := path[1]
Manikkaraj kb1a10922019-07-29 12:10:34 -0400321 if metadataFromwriteMetadata != 0 {
khenaidoo89b0e942018-10-21 21:11:33 -0400322 log.Debugw("creating-metadata-flow", log.Fields{"flow": flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400323 portNumber := fu.GetEgressPortNumberFromWriteMetadata(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400324 if portNumber != 0 {
khenaidoo820197c2020-02-13 16:35:33 -0500325 recalculatedRoute, err := agent.GetRoute(ctx, inPortNo, portNumber)
326 if err != nil {
327 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "metadata": metadataFromwriteMetadata, "error": err})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800328 return deviceRules, nil
khenaidoo820197c2020-02-13 16:35:33 -0500329 }
khenaidoo89b0e942018-10-21 21:11:33 -0400330 switch len(recalculatedRoute) {
331 case 0:
Manikkaraj kb1a10922019-07-29 12:10:34 -0400332 log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
333 //TODO: Delete flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800334 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400335 case 2:
khenaidood20a5852018-10-22 22:09:55 -0400336 log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop})
khenaidoo89b0e942018-10-21 21:11:33 -0400337 default:
khenaidoo820197c2020-02-13 16:35:33 -0500338 log.Errorw("invalid-route-length", log.Fields{"routeLen": len(path)})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800339 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400340 }
341 ingressHop = recalculatedRoute[0]
342 }
khenaidoo68c930b2019-05-13 11:46:51 -0400343 innerTag := fu.GetInnerTagFromMetaData(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400344 if innerTag == 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400345 log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": metadataFromwriteMetadata})
346 //TODO: Delete flow
Scott Bakerfdea1e32020-02-21 15:35:41 -0800347 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400348 }
npujar1d86a522019-11-14 17:11:16 +0530349 fa := &fu.FlowArgs{
350 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400351 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400352 fu.InPort(ingressHop.Ingress),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400353 fu.Metadata_ofp(uint64(innerTag)),
khenaidoo68c930b2019-05-13 11:46:51 -0400354 fu.TunnelId(uint64(portNumber)),
khenaidoo89b0e942018-10-21 21:11:33 -0400355 },
khenaidoo68c930b2019-05-13 11:46:51 -0400356 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400357 }
358 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400359 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...)
khenaidood20a5852018-10-22 22:09:55 -0400360
361 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400362 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400363
khenaidoo89b0e942018-10-21 21:11:33 -0400364 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800365 fs, err := fu.MkFlowStat(fa)
366 if err != nil {
367 return nil, err
368 }
369 fg.AddFlow(fs)
khenaidoo89b0e942018-10-21 21:11:33 -0400370 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
371 } else { // Create standard flow
372 log.Debugw("creating-standard-flow", log.Fields{"flow": flow})
npujar1d86a522019-11-14 17:11:16 +0530373 fa := &fu.FlowArgs{
374 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
khenaidoo89b0e942018-10-21 21:11:33 -0400375 MatchFields: []*ofp.OfpOxmOfbField{
khenaidoo68c930b2019-05-13 11:46:51 -0400376 fu.InPort(ingressHop.Ingress),
377 fu.TunnelId(uint64(inPortNo)),
khenaidoo89b0e942018-10-21 21:11:33 -0400378 },
khenaidoo68c930b2019-05-13 11:46:51 -0400379 Actions: fu.GetActions(flow),
khenaidoo89b0e942018-10-21 21:11:33 -0400380 }
381 // Augment the matchfields with the ofpfields from the flow
khenaidoo68c930b2019-05-13 11:46:51 -0400382 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400383
384 // Augment the Actions
khenaidoo68c930b2019-05-13 11:46:51 -0400385 fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress))
khenaidood20a5852018-10-22 22:09:55 -0400386
khenaidoo89b0e942018-10-21 21:11:33 -0400387 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800388 fs, err := fu.MkFlowStat(fa)
389 if err != nil {
390 return nil, err
391 }
392 fg.AddFlow(fs)
khenaidoo89b0e942018-10-21 21:11:33 -0400393 deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg)
394 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400395
Scott Bakerfdea1e32020-02-21 15:35:41 -0800396 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400397}
398
khenaidood20a5852018-10-22 22:09:55 -0400399// processUnicastFlow decomposes unicast flows
khenaidoo820197c2020-02-13 16:35:33 -0500400func (fd *FlowDecomposer) processUnicastFlow(ctx context.Context, path []route.Hop,
Scott Bakerfdea1e32020-02-21 15:35:41 -0800401 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400402
Manikkaraj kb1a10922019-07-29 12:10:34 -0400403 log.Debugw("decomposing-onu-flow-in-downstream-unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400404 deviceRules := fu.NewDeviceRules()
405
khenaidoo820197c2020-02-13 16:35:33 -0500406 egressHop := path[1]
khenaidood20a5852018-10-22 22:09:55 -0400407
npujar1d86a522019-11-14 17:11:16 +0530408 meterID := fu.GetMeterIdFromFlow(flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400409 metadataFromwriteMetadata := fu.GetMetadataFromWriteMetadataAction(flow)
npujar1d86a522019-11-14 17:11:16 +0530410 fa := &fu.FlowArgs{
411 KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie, "meter_id": uint64(meterID), "write_metadata": metadataFromwriteMetadata},
Manikkaraj kb1a10922019-07-29 12:10:34 -0400412 MatchFields: []*ofp.OfpOxmOfbField{
413 fu.InPort(egressHop.Ingress),
414 },
khenaidoo89b0e942018-10-21 21:11:33 -0400415 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400416 // Augment the matchfields with the ofpfields from the flow
417 fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...)
khenaidood20a5852018-10-22 22:09:55 -0400418
Manikkaraj kb1a10922019-07-29 12:10:34 -0400419 // Augment the Actions
420 filteredAction := fu.GetActions(flow, fu.OUTPUT)
421 filteredAction = append(filteredAction, fu.Output(egressHop.Egress))
422 fa.Actions = filteredAction
khenaidoo89b0e942018-10-21 21:11:33 -0400423
Manikkaraj kb1a10922019-07-29 12:10:34 -0400424 fg := fu.NewFlowsAndGroups()
Scott Bakerfdea1e32020-02-21 15:35:41 -0800425 fs, err := fu.MkFlowStat(fa)
426 if err != nil {
427 return nil, err
428 }
429 fg.AddFlow(fs)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400430 deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg)
Scott Bakerfdea1e32020-02-21 15:35:41 -0800431 return deviceRules, nil
khenaidoo89b0e942018-10-21 21:11:33 -0400432}
433
khenaidood20a5852018-10-22 22:09:55 -0400434// processMulticastFlow decompose multicast flows
khenaidoo820197c2020-02-13 16:35:33 -0500435func (fd *FlowDecomposer) processMulticastFlow(ctx context.Context, path []route.Hop,
npujar1d86a522019-11-14 17:11:16 +0530436 inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpID uint32,
khenaidood20a5852018-10-22 22:09:55 -0400437 groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules {
438
khenaidoo89b0e942018-10-21 21:11:33 -0400439 log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo})
khenaidood20a5852018-10-22 22:09:55 -0400440 deviceRules := fu.NewDeviceRules()
khenaidoo89b0e942018-10-21 21:11:33 -0400441
442 //having no Group yet is the same as having a Group with no buckets
443 var grp *ofp.OfpGroupEntry
444 var ok bool
npujar1d86a522019-11-14 17:11:16 +0530445 if grp, ok = groupMap[grpID]; !ok {
446 log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpID, "groupMap": groupMap})
khenaidoo89b0e942018-10-21 21:11:33 -0400447 return deviceRules
448 }
449 if grp == nil || grp.Desc == nil {
npujar1d86a522019-11-14 17:11:16 +0530450 log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpID, "grp": grp})
khenaidoo89b0e942018-10-21 21:11:33 -0400451 return deviceRules
452 }
khenaidoo89b0e942018-10-21 21:11:33 -0400453
khenaidoo820197c2020-02-13 16:35:33 -0500454 deviceRules.CreateEntryIfNotExist(path[0].DeviceID)
Esin Karaman09959ae2019-11-29 13:59:58 +0000455 fg := fu.NewFlowsAndGroups()
456 fg.AddFlow(flow)
457 //return the multicast flow without decomposing it
khenaidoo820197c2020-02-13 16:35:33 -0500458 deviceRules.AddFlowsAndGroup(path[0].DeviceID, fg)
khenaidoo89b0e942018-10-21 21:11:33 -0400459 return deviceRules
460}
461
khenaidood20a5852018-10-22 22:09:55 -0400462// decomposeFlow decomposes a flow for a logical device into flows for each physical device
npujar467fe752020-01-16 20:17:45 +0530463func (fd *FlowDecomposer) decomposeFlow(ctx context.Context, agent coreif.LogicalDeviceAgent, flow *ofp.OfpFlowStats,
khenaidoo820197c2020-02-13 16:35:33 -0500464 groupMap map[uint32]*ofp.OfpGroupEntry) (*fu.DeviceRules, error) {
khenaidood20a5852018-10-22 22:09:55 -0400465
khenaidoo68c930b2019-05-13 11:46:51 -0400466 inPortNo := fu.GetInPort(flow)
Esin Karaman09959ae2019-11-29 13:59:58 +0000467 if fu.HasGroup(flow) && inPortNo == 0 {
468 //if no in-port specified for a multicast flow, put NNI port as in-port
khenaidoo820197c2020-02-13 16:35:33 -0500469 //so that a valid path can be found for the flow
Esin Karaman09959ae2019-11-29 13:59:58 +0000470 nniPorts := agent.GetNNIPorts()
471 if len(nniPorts) > 0 {
472 inPortNo = nniPorts[0]
khenaidoo820197c2020-02-13 16:35:33 -0500473 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 +0000474 }
475 }
khenaidoo68c930b2019-05-13 11:46:51 -0400476 outPortNo := fu.GetOutPort(flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400477 deviceRules := fu.NewDeviceRules()
khenaidoo820197c2020-02-13 16:35:33 -0500478 path, err := agent.GetRoute(ctx, inPortNo, outPortNo)
479 if err != nil {
480 log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "error": err})
481 return deviceRules, err
482 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400483
khenaidoo820197c2020-02-13 16:35:33 -0500484 switch len(path) {
khenaidoo89b0e942018-10-21 21:11:33 -0400485 case 0:
khenaidoo820197c2020-02-13 16:35:33 -0500486 return deviceRules, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", inPortNo, outPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -0400487 case 2:
khenaidoo820197c2020-02-13 16:35:33 -0500488 log.Debugw("route-found", log.Fields{"ingressHop": path[0], "egressHop": path[1]})
khenaidoo89b0e942018-10-21 21:11:33 -0400489 default:
khenaidoo820197c2020-02-13 16:35:33 -0500490 return deviceRules, status.Errorf(codes.Aborted, "invalid route length %d", len(path))
khenaidoo89b0e942018-10-21 21:11:33 -0400491 }
492
khenaidoo89b0e942018-10-21 21:11:33 -0400493 // Process controller bound flow
494 if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) {
Scott Bakerfdea1e32020-02-21 15:35:41 -0800495 deviceRules, err = fd.processControllerBoundFlow(ctx, agent, path, inPortNo, outPortNo, flow)
496 if err != nil {
497 return nil, err
498 }
khenaidoo89b0e942018-10-21 21:11:33 -0400499 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500500 var ingressDevice *voltha.Device
501 var err error
khenaidoo820197c2020-02-13 16:35:33 -0500502 if ingressDevice, err = fd.deviceMgr.GetDevice(ctx, path[0].DeviceID); err != nil {
503 return deviceRules, err
khenaidoo297cd252019-02-07 22:10:23 -0500504 }
505 isUpstream := !ingressDevice.Root
Manikkaraj kb1a10922019-07-29 12:10:34 -0400506 if isUpstream { // Unicast OLT and ONU UL
khenaidoo820197c2020-02-13 16:35:33 -0500507 log.Debug("process-olt-nd-onu-upstream-noncontrollerbound-unicast-flows", log.Fields{"flows": flow})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800508 deviceRules, err = fd.processUpstreamNonControllerBoundFlow(ctx, path, inPortNo, outPortNo, flow)
509 if err != nil {
510 return nil, err
511 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400512 } else if fu.HasNextTable(flow) && flow.TableId == 0 { // Unicast OLT flow DL
khenaidoo820197c2020-02-13 16:35:33 -0500513 log.Debugw("process-olt-downstream-noncontrollerbound-flow-with-nexttable", log.Fields{"flows": flow})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800514 deviceRules, err = fd.processDownstreamFlowWithNextTable(ctx, agent, path, inPortNo, outPortNo, flow)
515 if err != nil {
516 return nil, err
517 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400518 } else if flow.TableId == 1 && outPortNo != 0 { // Unicast ONU flow DL
khenaidoo820197c2020-02-13 16:35:33 -0500519 log.Debugw("process-onu-downstream-unicast-flow", log.Fields{"flows": flow})
Scott Bakerfdea1e32020-02-21 15:35:41 -0800520 deviceRules, err = fd.processUnicastFlow(ctx, path, inPortNo, outPortNo, flow)
521 if err != nil {
522 return nil, err
523 }
npujar1d86a522019-11-14 17:11:16 +0530524 } else if grpID := fu.GetGroup(flow); grpID != 0 && flow.TableId == 0 { //Multicast
khenaidoo820197c2020-02-13 16:35:33 -0500525 log.Debugw("process-multicast-flow", log.Fields{"flows": flow})
526 deviceRules = fd.processMulticastFlow(ctx, path, inPortNo, outPortNo, flow, grpID, groupMap)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400527 } else {
khenaidoo820197c2020-02-13 16:35:33 -0500528 return deviceRules, status.Errorf(codes.Aborted, "unknown downstream flow %v", *flow)
khenaidoo89b0e942018-10-21 21:11:33 -0400529 }
530 }
Scott Bakerfdea1e32020-02-21 15:35:41 -0800531 deviceRules, err = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules)
532 return deviceRules, err
khenaidoo89b0e942018-10-21 21:11:33 -0400533}