khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package flow_decomposition |
| 18 | |
| 19 | import ( |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 20 | "github.com/gogo/protobuf/proto" |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 21 | "github.com/opencord/voltha-go/common/log" |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 22 | "github.com/opencord/voltha-go/rw_core/coreIf" |
| 23 | "github.com/opencord/voltha-go/rw_core/graph" |
| 24 | fu "github.com/opencord/voltha-go/rw_core/utils" |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 25 | ofp "github.com/opencord/voltha-protos/go/openflow_13" |
| 26 | "github.com/opencord/voltha-protos/go/voltha" |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 27 | ) |
| 28 | |
| 29 | func init() { |
| 30 | log.AddPackage(log.JSON, log.DebugLevel, nil) |
| 31 | } |
| 32 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 33 | type FlowDecomposer struct { |
| 34 | deviceMgr coreIf.DeviceManager |
| 35 | } |
| 36 | |
| 37 | func NewFlowDecomposer(deviceMgr coreIf.DeviceManager) *FlowDecomposer { |
| 38 | var decomposer FlowDecomposer |
| 39 | decomposer.deviceMgr = deviceMgr |
| 40 | return &decomposer |
| 41 | } |
| 42 | |
| 43 | //DecomposeRules decomposes per-device flows and flow-groups from the flows and groups defined on a logical device |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 44 | func (fd *FlowDecomposer) DecomposeRules(agent coreIf.LogicalDeviceAgent, flows ofp.Flows, groups ofp.FlowGroups, includeDefaultFlows bool) *fu.DeviceRules { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 45 | rules := agent.GetAllDefaultRules() |
| 46 | deviceRules := rules.Copy() |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 47 | devicesToUpdate := make(map[string]string) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 48 | |
| 49 | groupMap := make(map[uint32]*ofp.OfpGroupEntry) |
| 50 | for _, groupEntry := range groups.Items { |
| 51 | groupMap[groupEntry.Desc.GroupId] = groupEntry |
| 52 | } |
| 53 | |
| 54 | var decomposedRules *fu.DeviceRules |
| 55 | for _, flow := range flows.Items { |
| 56 | decomposedRules = fd.decomposeFlow(agent, flow, groupMap) |
| 57 | for deviceId, flowAndGroups := range decomposedRules.Rules { |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 58 | deviceRules.CreateEntryIfNotExist(deviceId) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 59 | deviceRules.Rules[deviceId].AddFrom(flowAndGroups) |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 60 | devicesToUpdate[deviceId] = deviceId |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 61 | } |
| 62 | } |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 63 | if includeDefaultFlows { |
| 64 | return deviceRules |
| 65 | } |
| 66 | updatedDeviceRules := deviceRules.FilterRules(devicesToUpdate) |
| 67 | |
| 68 | return updatedDeviceRules |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 69 | } |
| 70 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 71 | // Handles special case of any controller-bound flow for a parent device |
| 72 | func (fd *FlowDecomposer) updateOutputPortForControllerBoundFlowForParentDevide(flow *ofp.OfpFlowStats, |
| 73 | dr *fu.DeviceRules) *fu.DeviceRules { |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 74 | EAPOL := fu.EthType(0x888e) |
| 75 | IGMP := fu.IpProto(2) |
| 76 | UDP := fu.IpProto(17) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 77 | |
| 78 | newDeviceRules := dr.Copy() |
| 79 | // Check whether we are dealing with a parent device |
| 80 | for deviceId, fg := range dr.GetRules() { |
| 81 | if root, _ := fd.deviceMgr.IsRootDevice(deviceId); root { |
| 82 | newDeviceRules.ClearFlows(deviceId) |
| 83 | for i := 0; i < fg.Flows.Len(); i++ { |
| 84 | f := fg.GetFlow(i) |
| 85 | UpdateOutPortNo := false |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 86 | for _, field := range fu.GetOfbFields(f) { |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 87 | UpdateOutPortNo = (field.String() == EAPOL.String()) |
| 88 | UpdateOutPortNo = UpdateOutPortNo || (field.String() == IGMP.String()) |
| 89 | UpdateOutPortNo = UpdateOutPortNo || (field.String() == UDP.String()) |
| 90 | if UpdateOutPortNo { |
| 91 | break |
| 92 | } |
| 93 | } |
| 94 | if UpdateOutPortNo { |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 95 | f = fu.UpdateOutputPortByActionType(f, uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS), |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 96 | uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) |
| 97 | } |
| 98 | // Update flow Id as a change in the instruction field will result in a new flow ID |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 99 | f.Id = fu.HashFlowStats(f) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 100 | newDeviceRules.AddFlow(deviceId, (proto.Clone(f)).(*ofp.OfpFlowStats)) |
| 101 | } |
| 102 | } |
| 103 | } |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 104 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 105 | return newDeviceRules |
| 106 | } |
| 107 | |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 108 | //processControllerBoundFlow decomposes trap flows |
| 109 | func (fd *FlowDecomposer) processControllerBoundFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop, |
| 110 | inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules { |
| 111 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 112 | log.Debugw("trap-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "flow": flow}) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 113 | deviceRules := fu.NewDeviceRules() |
| 114 | |
| 115 | egressHop := route[1] |
| 116 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 117 | fg := fu.NewFlowsAndGroups() |
| 118 | if agent.GetDeviceGraph().IsRootPort(inPortNo) { |
| 119 | log.Debug("trap-nni") |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 120 | // no decomposition required - it is already an OLT flow from NNI |
| 121 | fg.AddFlow(flow) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 122 | } else { |
| 123 | // Trap flow for UNI port |
| 124 | log.Debug("trap-uni") |
| 125 | |
| 126 | //inPortNo is 0 for wildcard input case, do not include upstream port for 4000 flow in input |
| 127 | var inPorts []uint32 |
| 128 | if inPortNo == 0 { |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 129 | inPorts = agent.GetWildcardInputPorts(egressHop.Egress) // exclude egress_hop.egress_port.port_no |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 130 | } else { |
| 131 | inPorts = []uint32{inPortNo} |
| 132 | } |
| 133 | for _, inputPort := range inPorts { |
| 134 | var fa *fu.FlowArgs |
| 135 | // Upstream flow |
| 136 | fa = &fu.FlowArgs{ |
| 137 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 138 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 139 | fu.InPort(egressHop.Ingress), |
| 140 | fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | inputPort), |
| 141 | fu.TunnelId(uint64(inputPort)), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 142 | }, |
| 143 | Actions: []*ofp.OfpAction{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 144 | fu.PushVlan(0x8100), |
| 145 | fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)), |
| 146 | fu.Output(egressHop.Egress), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 147 | }, |
| 148 | } |
| 149 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 150 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID)...) |
| 151 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 152 | |
| 153 | // Downstream flow |
| 154 | fa = &fu.FlowArgs{ |
| 155 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority)}, |
| 156 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 157 | fu.InPort(egressHop.Egress), |
| 158 | fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000), |
| 159 | fu.VlanPcp(0), |
| 160 | fu.Metadata_ofp(uint64(inputPort)), |
| 161 | fu.TunnelId(uint64(inputPort)), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 162 | }, |
| 163 | Actions: []*ofp.OfpAction{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 164 | fu.PopVlan(), |
| 165 | fu.Output(egressHop.Ingress), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 166 | }, |
| 167 | } |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 168 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 169 | } |
| 170 | } |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 171 | deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg) |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 172 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 173 | return deviceRules |
| 174 | } |
| 175 | |
| 176 | // processUpstreamNonControllerBoundFlow processes non-controller bound flow. We assume that anything that is |
| 177 | // upstream needs to get Q-in-Q treatment and that this is expressed via two flow rules, the first using the |
| 178 | // goto-statement. We also assume that the inner tag is applied at the ONU, while the outer tag is |
| 179 | // applied at the OLT |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 180 | func (fd *FlowDecomposer) processUpstreamNonControllerBoundFlow(agent coreIf.LogicalDeviceAgent, |
| 181 | route []graph.RouteHop, inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules { |
| 182 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 183 | log.Debugw("upstream-non-controller-bound-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo}) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 184 | deviceRules := fu.NewDeviceRules() |
| 185 | |
| 186 | ingressHop := route[0] |
| 187 | egressHop := route[1] |
| 188 | |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 189 | if fu.HasNextTable(flow) { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 190 | log.Debugw("has-next-table", log.Fields{"table_id": flow.TableId}) |
| 191 | if outPortNo != 0 { |
| 192 | log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo}) |
| 193 | } |
| 194 | var fa *fu.FlowArgs |
| 195 | fa = &fu.FlowArgs{ |
| 196 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 197 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 198 | fu.InPort(ingressHop.Ingress), |
| 199 | fu.TunnelId(uint64(inPortNo)), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 200 | }, |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 201 | Actions: fu.GetActions(flow), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 202 | } |
| 203 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 204 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 205 | |
| 206 | // Augment the Actions |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 207 | fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 208 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 209 | fg := fu.NewFlowsAndGroups() |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 210 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 211 | deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 212 | } else { |
| 213 | var actions []ofp.OfpActionType |
| 214 | var isOutputTypeInActions bool |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 215 | for _, action := range fu.GetActions(flow) { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 216 | actions = append(actions, action.Type) |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 217 | if !isOutputTypeInActions && action.Type == fu.OUTPUT { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 218 | isOutputTypeInActions = true |
| 219 | } |
| 220 | } |
| 221 | if len(actions) == 1 && isOutputTypeInActions { |
| 222 | var fa *fu.FlowArgs |
| 223 | // child device flow |
| 224 | fa = &fu.FlowArgs{ |
| 225 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 226 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 227 | fu.InPort(ingressHop.Ingress), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 228 | }, |
| 229 | Actions: []*ofp.OfpAction{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 230 | fu.Output(ingressHop.Egress), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 231 | }, |
| 232 | } |
| 233 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 234 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 235 | fg := fu.NewFlowsAndGroups() |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 236 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 237 | deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 238 | |
| 239 | // parent device flow |
| 240 | fa = &fu.FlowArgs{ |
| 241 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 242 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 243 | fu.InPort(egressHop.Ingress), //egress_hop.ingress_port.port_no |
| 244 | fu.TunnelId(uint64(inPortNo)), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 245 | }, |
| 246 | Actions: []*ofp.OfpAction{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 247 | fu.Output(egressHop.Egress), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 248 | }, |
| 249 | } |
| 250 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 251 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 252 | fg = fu.NewFlowsAndGroups() |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 253 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 254 | deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 255 | } else { |
| 256 | if outPortNo == 0 { |
| 257 | log.Warnw("outPort-should-be-specified", log.Fields{"outPortNo": outPortNo}) |
| 258 | } |
| 259 | var fa *fu.FlowArgs |
| 260 | fa = &fu.FlowArgs{ |
| 261 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 262 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 263 | fu.InPort(egressHop.Ingress), |
| 264 | fu.TunnelId(uint64(inPortNo)), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 265 | }, |
| 266 | } |
| 267 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 268 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 269 | |
| 270 | //Augment the actions |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 271 | filteredAction := fu.GetActions(flow, fu.OUTPUT) |
| 272 | filteredAction = append(filteredAction, fu.Output(egressHop.Egress)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 273 | fa.Actions = filteredAction |
| 274 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 275 | fg := fu.NewFlowsAndGroups() |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 276 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 277 | deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 278 | } |
| 279 | } |
| 280 | return deviceRules |
| 281 | } |
| 282 | |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 283 | // processDownstreamFlowWithNextTable decomposes downstream flows containing next table ID instructions |
| 284 | func (fd *FlowDecomposer) processDownstreamFlowWithNextTable(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop, |
| 285 | inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules { |
| 286 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 287 | log.Debugw("downstream-flow-with-next-table", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo}) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 288 | deviceRules := fu.NewDeviceRules() |
| 289 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 290 | if outPortNo != 0 { |
| 291 | log.Warnw("outPort-should-not-be-specified", log.Fields{"outPortNo": outPortNo}) |
| 292 | } |
| 293 | ingressHop := route[0] |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 294 | egressHop := route[1] |
| 295 | |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 296 | if fu.GetMetaData(flow) != 0 { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 297 | log.Debugw("creating-metadata-flow", log.Fields{"flow": flow}) |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 298 | portNumber := uint32(fu.GetPortNumberFromMetadata(flow)) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 299 | if portNumber != 0 { |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 300 | recalculatedRoute := agent.GetRoute(inPortNo, portNumber) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 301 | switch len(recalculatedRoute) { |
| 302 | case 0: |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 303 | log.Errorw("no-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": fu.GetMetaData64Bit(flow)}) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 304 | // TODO: Delete flow |
| 305 | return deviceRules |
| 306 | case 2: |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 307 | log.Debugw("route-found", log.Fields{"ingressHop": ingressHop, "egressHop": egressHop}) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 308 | break |
| 309 | default: |
| 310 | log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)}) |
| 311 | return deviceRules |
| 312 | } |
| 313 | ingressHop = recalculatedRoute[0] |
| 314 | } |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 315 | innerTag := fu.GetInnerTagFromMetaData(flow) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 316 | if innerTag == 0 { |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 317 | log.Errorw("no-inner-route-double-tag", log.Fields{"inPortNo": inPortNo, "outPortNo": portNumber, "comment": "deleting-flow", "metadata": fu.GetMetaData64Bit(flow)}) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 318 | // TODO: Delete flow |
| 319 | return deviceRules |
| 320 | } |
| 321 | var fa *fu.FlowArgs |
| 322 | fa = &fu.FlowArgs{ |
| 323 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 324 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 325 | fu.InPort(ingressHop.Ingress), |
| 326 | fu.Metadata_ofp(innerTag), |
| 327 | fu.TunnelId(uint64(portNumber)), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 328 | }, |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 329 | Actions: fu.GetActions(flow), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 330 | } |
| 331 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 332 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.METADATA)...) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 333 | |
| 334 | // Augment the Actions |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 335 | fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 336 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 337 | fg := fu.NewFlowsAndGroups() |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 338 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 339 | deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg) |
| 340 | } else { // Create standard flow |
| 341 | log.Debugw("creating-standard-flow", log.Fields{"flow": flow}) |
| 342 | var fa *fu.FlowArgs |
| 343 | fa = &fu.FlowArgs{ |
| 344 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 345 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 346 | fu.InPort(ingressHop.Ingress), |
| 347 | fu.TunnelId(uint64(inPortNo)), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 348 | }, |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 349 | Actions: fu.GetActions(flow), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 350 | } |
| 351 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 352 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 353 | |
| 354 | // Augment the Actions |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 355 | fa.Actions = append(fa.Actions, fu.Output(ingressHop.Egress)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 356 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 357 | fg := fu.NewFlowsAndGroups() |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 358 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 359 | deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg) |
| 360 | } |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 361 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 362 | return deviceRules |
| 363 | } |
| 364 | |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 365 | // processUnicastFlow decomposes unicast flows |
| 366 | func (fd *FlowDecomposer) processUnicastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop, |
| 367 | inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats) *fu.DeviceRules { |
| 368 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 369 | log.Debugw("unicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo}) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 370 | deviceRules := fu.NewDeviceRules() |
| 371 | |
| 372 | ingressHop := route[0] |
| 373 | egressHop := route[1] |
| 374 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 375 | var actions []ofp.OfpActionType |
| 376 | var isOutputTypeInActions bool |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 377 | for _, action := range fu.GetActions(flow) { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 378 | actions = append(actions, action.Type) |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 379 | if !isOutputTypeInActions && action.Type == fu.OUTPUT { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 380 | isOutputTypeInActions = true |
| 381 | } |
| 382 | } |
| 383 | if len(actions) == 1 && isOutputTypeInActions { |
| 384 | var fa *fu.FlowArgs |
| 385 | // Parent device flow |
| 386 | fa = &fu.FlowArgs{ |
| 387 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 388 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 389 | fu.InPort(ingressHop.Ingress), |
| 390 | fu.TunnelId(uint64(inPortNo)), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 391 | }, |
| 392 | Actions: []*ofp.OfpAction{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 393 | fu.Output(ingressHop.Egress), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 394 | }, |
| 395 | } |
| 396 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 397 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 398 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 399 | fg := fu.NewFlowsAndGroups() |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 400 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 401 | deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 402 | |
| 403 | // Child device flow |
| 404 | fa = &fu.FlowArgs{ |
| 405 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 406 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 407 | fu.InPort(egressHop.Ingress), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 408 | }, |
| 409 | Actions: []*ofp.OfpAction{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 410 | fu.Output(egressHop.Egress), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 411 | }, |
| 412 | } |
| 413 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 414 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 415 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 416 | fg = fu.NewFlowsAndGroups() |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 417 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 418 | deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 419 | } else { |
| 420 | var fa *fu.FlowArgs |
| 421 | fa = &fu.FlowArgs{ |
| 422 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 423 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 424 | fu.InPort(egressHop.Ingress), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 425 | }, |
| 426 | } |
| 427 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 428 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 429 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 430 | // Augment the Actions |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 431 | filteredAction := fu.GetActions(flow, fu.OUTPUT) |
| 432 | filteredAction = append(filteredAction, fu.Output(egressHop.Egress)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 433 | fa.Actions = filteredAction |
| 434 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 435 | fg := fu.NewFlowsAndGroups() |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 436 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 437 | deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 438 | } |
| 439 | return deviceRules |
| 440 | } |
| 441 | |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 442 | // processMulticastFlow decompose multicast flows |
| 443 | func (fd *FlowDecomposer) processMulticastFlow(agent coreIf.LogicalDeviceAgent, route []graph.RouteHop, |
| 444 | inPortNo uint32, outPortNo uint32, flow *ofp.OfpFlowStats, grpId uint32, |
| 445 | groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules { |
| 446 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 447 | log.Debugw("multicast-flow", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo}) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 448 | deviceRules := fu.NewDeviceRules() |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 449 | |
| 450 | //having no Group yet is the same as having a Group with no buckets |
| 451 | var grp *ofp.OfpGroupEntry |
| 452 | var ok bool |
| 453 | if grp, ok = groupMap[grpId]; !ok { |
| 454 | log.Warnw("Group-id-not-present-in-map", log.Fields{"grpId": grpId, "groupMap": groupMap}) |
| 455 | return deviceRules |
| 456 | } |
| 457 | if grp == nil || grp.Desc == nil { |
| 458 | log.Warnw("Group-or-desc-nil", log.Fields{"grpId": grpId, "grp": grp}) |
| 459 | return deviceRules |
| 460 | } |
| 461 | for _, bucket := range grp.Desc.Buckets { |
| 462 | otherActions := make([]*ofp.OfpAction, 0) |
| 463 | for _, action := range bucket.Actions { |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 464 | if action.Type == fu.OUTPUT { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 465 | outPortNo = action.GetOutput().Port |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 466 | } else if action.Type != fu.POP_VLAN { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 467 | otherActions = append(otherActions, action) |
| 468 | } |
| 469 | } |
| 470 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 471 | route2 := agent.GetRoute(inPortNo, outPortNo) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 472 | switch len(route2) { |
| 473 | case 0: |
| 474 | log.Errorw("mc-no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting flow"}) |
| 475 | // TODO: Delete flow |
| 476 | return deviceRules |
| 477 | case 2: |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 478 | log.Debugw("route-found", log.Fields{"ingressHop": route2[0], "egressHop": route2[1]}) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 479 | break |
| 480 | default: |
| 481 | log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)}) |
| 482 | return deviceRules |
| 483 | } |
| 484 | |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 485 | ingressHop := route[0] |
| 486 | ingressHop2 := route2[0] |
| 487 | egressHop := route2[1] |
| 488 | |
| 489 | if ingressHop.Ingress != ingressHop2.Ingress { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 490 | log.Errorw("mc-ingress-hop-hop2-mismatch", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "ignoring flow"}) |
| 491 | return deviceRules |
| 492 | } |
| 493 | // Set the parent device flow |
| 494 | var fa *fu.FlowArgs |
| 495 | fa = &fu.FlowArgs{ |
| 496 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 497 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 498 | fu.InPort(ingressHop.Ingress), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 499 | }, |
| 500 | } |
| 501 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 502 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT)...) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 503 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 504 | // Augment the Actions |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 505 | filteredAction := fu.GetActions(flow, fu.GROUP) |
| 506 | filteredAction = append(filteredAction, fu.PopVlan()) |
| 507 | filteredAction = append(filteredAction, fu.Output(route2[1].Ingress)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 508 | fa.Actions = filteredAction |
| 509 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 510 | fg := fu.NewFlowsAndGroups() |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 511 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 512 | deviceRules.AddFlowsAndGroup(ingressHop.DeviceID, fg) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 513 | |
| 514 | // Set the child device flow |
| 515 | fa = &fu.FlowArgs{ |
| 516 | KV: fu.OfpFlowModArgs{"priority": uint64(flow.Priority), "cookie": flow.Cookie}, |
| 517 | MatchFields: []*ofp.OfpOxmOfbField{ |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 518 | fu.InPort(egressHop.Ingress), |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 519 | }, |
| 520 | } |
| 521 | // Augment the matchfields with the ofpfields from the flow |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 522 | fa.MatchFields = append(fa.MatchFields, fu.GetOfbFields(flow, fu.IN_PORT, fu.VLAN_VID, fu.VLAN_PCP)...) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 523 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 524 | // Augment the Actions |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 525 | otherActions = append(otherActions, fu.Output(egressHop.Egress)) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 526 | fa.Actions = otherActions |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 527 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 528 | fg = fu.NewFlowsAndGroups() |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 529 | fg.AddFlow(fu.MkFlowStat(fa)) |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 530 | deviceRules.AddFlowsAndGroup(egressHop.DeviceID, fg) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 531 | } |
| 532 | return deviceRules |
| 533 | } |
| 534 | |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 535 | // decomposeFlow decomposes a flow for a logical device into flows for each physical device |
| 536 | func (fd *FlowDecomposer) decomposeFlow(agent coreIf.LogicalDeviceAgent, flow *ofp.OfpFlowStats, |
| 537 | groupMap map[uint32]*ofp.OfpGroupEntry) *fu.DeviceRules { |
| 538 | |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 539 | inPortNo := fu.GetInPort(flow) |
| 540 | outPortNo := fu.GetOutPort(flow) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 541 | deviceRules := fu.NewDeviceRules() |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 542 | route := agent.GetRoute(inPortNo, outPortNo) |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 543 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 544 | switch len(route) { |
| 545 | case 0: |
| 546 | log.Errorw("no-route", log.Fields{"inPortNo": inPortNo, "outPortNo": outPortNo, "comment": "deleting-flow"}) |
| 547 | // TODO: Delete flow |
| 548 | return deviceRules |
| 549 | case 2: |
| 550 | log.Debugw("route-found", log.Fields{"ingressHop": route[0], "egressHop": route[1]}) |
| 551 | break |
| 552 | default: |
| 553 | log.Errorw("invalid-route-length", log.Fields{"routeLen": len(route)}) |
| 554 | return deviceRules |
| 555 | } |
| 556 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 557 | // Process controller bound flow |
| 558 | if outPortNo != 0 && (outPortNo&0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER) { |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 559 | deviceRules = fd.processControllerBoundFlow(agent, route, inPortNo, outPortNo, flow) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 560 | } else { |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 561 | var ingressDevice *voltha.Device |
| 562 | var err error |
| 563 | if ingressDevice, err = fd.deviceMgr.GetDevice(route[0].DeviceID); err != nil { |
| 564 | log.Errorw("ingress-device-not-found", log.Fields{"deviceId": route[0].DeviceID, "flow": flow}) |
| 565 | return deviceRules |
| 566 | } |
| 567 | isUpstream := !ingressDevice.Root |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 568 | if isUpstream { |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 569 | deviceRules = fd.processUpstreamNonControllerBoundFlow(agent, route, inPortNo, outPortNo, flow) |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 570 | } else if fu.HasNextTable(flow) { |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 571 | deviceRules = fd.processDownstreamFlowWithNextTable(agent, route, inPortNo, outPortNo, flow) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 572 | } else if outPortNo != 0 { // Unicast |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 573 | deviceRules = fd.processUnicastFlow(agent, route, inPortNo, outPortNo, flow) |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 574 | } else if grpId := fu.GetGroup(flow); grpId != 0 { //Multicast |
khenaidoo | d20a585 | 2018-10-22 22:09:55 -0400 | [diff] [blame] | 575 | deviceRules = fd.processMulticastFlow(agent, route, inPortNo, outPortNo, flow, grpId, groupMap) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 576 | } |
| 577 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 578 | deviceRules = fd.updateOutputPortForControllerBoundFlowForParentDevide(flow, deviceRules) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 579 | return deviceRules |
| 580 | } |