blob: 6fa6a02418a69710f51381b5e7a998b8d79e9c87 [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 */
16package utils
17
18import (
19 "bytes"
20 "github.com/cevaris/ordered_map"
21 "github.com/gogo/protobuf/proto"
22 ofp "github.com/opencord/voltha-go/protos/openflow_13"
khenaidoo19d7b632018-10-30 10:49:50 -040023 "strings"
khenaidoo89b0e942018-10-21 21:11:33 -040024)
25
26type OfpFlowModArgs map[string]uint64
27
28type FlowArgs struct {
29 MatchFields []*ofp.OfpOxmOfbField
30 Actions []*ofp.OfpAction
31 Command *ofp.OfpFlowModCommand
32 Priority uint32
33 KV OfpFlowModArgs
34}
35
khenaidood20a5852018-10-22 22:09:55 -040036type GroupArgs struct {
37 GroupId uint32
38 Buckets []*ofp.OfpBucket
39 Command *ofp.OfpGroupModCommand
40}
41
khenaidoo89b0e942018-10-21 21:11:33 -040042type FlowsAndGroups struct {
43 Flows *ordered_map.OrderedMap
44 Groups *ordered_map.OrderedMap
45}
46
47func NewFlowsAndGroups() *FlowsAndGroups {
48 var fg FlowsAndGroups
49 fg.Flows = ordered_map.NewOrderedMap()
50 fg.Groups = ordered_map.NewOrderedMap()
51 return &fg
52}
53
54func (fg *FlowsAndGroups) Copy() *FlowsAndGroups {
55 copyFG := NewFlowsAndGroups()
56 iter := fg.Flows.IterFunc()
57 for kv, ok := iter(); ok; kv, ok = iter() {
58 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
59 copyFG.Flows.Set(kv.Key, proto.Clone(protoMsg))
60 }
61 }
62 iter = fg.Groups.IterFunc()
63 for kv, ok := iter(); ok; kv, ok = iter() {
64 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
65 copyFG.Groups.Set(kv.Key, proto.Clone(protoMsg))
66 }
67 }
68 return copyFG
69}
70
71func (fg *FlowsAndGroups) GetFlow(index int) *ofp.OfpFlowStats {
72 iter := fg.Flows.IterFunc()
73 pos := 0
74 for kv, ok := iter(); ok; kv, ok = iter() {
75 if pos == index {
76 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
77 return protoMsg
78 }
79 return nil
80 }
81 pos += 1
82 }
83 return nil
84}
85
khenaidoo19d7b632018-10-30 10:49:50 -040086func (fg *FlowsAndGroups) ListFlows() []*ofp.OfpFlowStats {
87 flows := make([]*ofp.OfpFlowStats, 0)
88 iter := fg.Flows.IterFunc()
89 for kv, ok := iter(); ok; kv, ok = iter() {
90 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
91 flows = append(flows, protoMsg)
92 }
93 }
94 return flows
95}
96
97func (fg *FlowsAndGroups) ListGroups() []*ofp.OfpGroupEntry {
98 groups := make([]*ofp.OfpGroupEntry, 0)
99 iter := fg.Groups.IterFunc()
100 for kv, ok := iter(); ok; kv, ok = iter() {
101 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
102 groups = append(groups, protoMsg)
103 }
104 }
105 return groups
106}
107
khenaidoo89b0e942018-10-21 21:11:33 -0400108func (fg *FlowsAndGroups) String() string {
109 var buffer bytes.Buffer
110 iter := fg.Flows.IterFunc()
111 for kv, ok := iter(); ok; kv, ok = iter() {
112 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
113 buffer.WriteString("\nFlow:\n")
114 buffer.WriteString(proto.MarshalTextString(protoMsg))
115 buffer.WriteString("\n")
116 }
117 }
118 iter = fg.Groups.IterFunc()
119 for kv, ok := iter(); ok; kv, ok = iter() {
120 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
121 buffer.WriteString("\nGroup:\n")
122 buffer.WriteString(proto.MarshalTextString(protoMsg))
123 buffer.WriteString("\n")
124 }
125 }
126 return buffer.String()
127}
128
129func (fg *FlowsAndGroups) AddFlow(flow *ofp.OfpFlowStats) {
130 if fg.Flows == nil {
131 fg.Flows = ordered_map.NewOrderedMap()
132 }
133 if fg.Groups == nil {
134 fg.Groups = ordered_map.NewOrderedMap()
135 }
136 //Add flow only if absent
137 if _, exist := fg.Flows.Get(flow.Id); !exist {
138 fg.Flows.Set(flow.Id, flow)
139 }
140}
141
142//AddFrom add flows and groups from the argument into this structure only if they do not already exist
143func (fg *FlowsAndGroups) AddFrom(from *FlowsAndGroups) {
144 iter := from.Flows.IterFunc()
145 for kv, ok := iter(); ok; kv, ok = iter() {
146 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
147 if _, exist := fg.Flows.Get(protoMsg.Id); !exist {
148 fg.Flows.Set(protoMsg.Id, protoMsg)
149 }
150 }
151 }
152 iter = from.Groups.IterFunc()
153 for kv, ok := iter(); ok; kv, ok = iter() {
154 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
155 if _, exist := fg.Groups.Get(protoMsg.Stats.GroupId); !exist {
156 fg.Groups.Set(protoMsg.Stats.GroupId, protoMsg)
157 }
158 }
159 }
160}
161
162type DeviceRules struct {
163 Rules map[string]*FlowsAndGroups
164}
165
166func NewDeviceRules() *DeviceRules {
167 var dr DeviceRules
168 dr.Rules = make(map[string]*FlowsAndGroups)
169 return &dr
170}
171
172func (dr *DeviceRules) Copy() *DeviceRules {
173 copyDR := NewDeviceRules()
174 for key, val := range dr.Rules {
175 copyDR.Rules[key] = val.Copy()
176 }
177 return copyDR
178}
179
khenaidoo19d7b632018-10-30 10:49:50 -0400180func (dr *DeviceRules) ClearFlows(deviceId string) {
181 if _, exist := dr.Rules[deviceId]; exist {
182 dr.Rules[deviceId].Flows = ordered_map.NewOrderedMap()
183 }
184}
185
186func (dr *DeviceRules) AddFlow(deviceId string, flow *ofp.OfpFlowStats) {
187 if _, exist := dr.Rules[deviceId]; !exist {
188 dr.Rules[deviceId] = NewFlowsAndGroups()
189 }
190 dr.Rules[deviceId].AddFlow(flow)
191}
192
193func (dr *DeviceRules) GetRules() map[string]*FlowsAndGroups {
194 return dr.Rules
195}
196
khenaidoo89b0e942018-10-21 21:11:33 -0400197func (dr *DeviceRules) String() string {
198 var buffer bytes.Buffer
199 for key, value := range dr.Rules {
200 buffer.WriteString("DeviceId:")
201 buffer.WriteString(key)
202 buffer.WriteString(value.String())
203 buffer.WriteString("\n\n")
204 }
205 return buffer.String()
206}
207
208func (dr *DeviceRules) AddFlowsAndGroup(deviceId string, fg *FlowsAndGroups) {
khenaidood20a5852018-10-22 22:09:55 -0400209 if _, ok := dr.Rules[deviceId]; !ok {
210 dr.Rules[deviceId] = NewFlowsAndGroups()
211 }
khenaidoo89b0e942018-10-21 21:11:33 -0400212 dr.Rules[deviceId] = fg
213}
khenaidood20a5852018-10-22 22:09:55 -0400214
215// CreateEntryIfNotExist creates a new deviceId in the Map if it does not exist and assigns an
216// empty FlowsAndGroups to it. Otherwise, it does nothing.
217func (dr *DeviceRules) CreateEntryIfNotExist(deviceId string) {
218 if _, ok := dr.Rules[deviceId]; !ok {
219 dr.Rules[deviceId] = NewFlowsAndGroups()
220 }
221}
khenaidoo19d7b632018-10-30 10:49:50 -0400222
223/*
224 * Common flow routines
225 */
226
227//FindOverlappingFlows return a list of overlapping flow(s) where mod is the flow request
228func FindOverlappingFlows(flows []*ofp.OfpFlowStats, mod *ofp.OfpFlowMod) []*ofp.OfpFlowStats {
229 return nil //TODO - complete implementation
230}
231
232// FindFlowById returns the index of the flow in the flows array if present. Otherwise, it returns -1
233func FindFlowById(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
234 for idx, f := range flows {
235 if flow.Id == f.Id {
236 return idx
237 }
238 }
239 return -1
240}
241
242// FindFlows returns the index in flows where flow if present. Otherwise, it returns -1
243func FindFlows(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
244 for idx, f := range flows {
245 if FlowMatch(f, flow) {
246 return idx
247 }
248 }
249 return -1
250}
251
252//FlowMatch returns true if two flows matches on the following flow attributes:
253//TableId, Priority, Flags, Cookie, Match
254func FlowMatch(f1 *ofp.OfpFlowStats, f2 *ofp.OfpFlowStats) bool {
255 keysMatter := []string{"TableId", "Priority", "Flags", "Cookie", "Match"}
256 for _, key := range keysMatter {
257 switch key {
258 case "TableId":
259 if f1.TableId != f2.TableId {
260 return false
261 }
262 case "Priority":
263 if f1.Priority != f2.Priority {
264 return false
265 }
266 case "Flags":
267 if f1.Flags != f2.Flags {
268 return false
269 }
270 case "Cookie":
271 if f1.Cookie != f2.Cookie {
272 return false
273 }
274 case "Match":
275 if strings.Compare(f1.Match.String(), f2.Match.String()) != 0 {
276 return false
277 }
278 }
279 }
280 return true
281}
282
283//FlowMatchesMod returns True if given flow is "covered" by the wildcard flow_mod, taking into consideration of
284//both exact matches as well as masks-based match fields if any. Otherwise return False
285func FlowMatchesMod(flow *ofp.OfpFlowStats, mod *ofp.OfpFlowMod) bool {
286 //Check if flow.cookie is covered by mod.cookie and mod.cookie_mask
287 if (flow.Cookie & mod.CookieMask) != (mod.Cookie & mod.CookieMask) {
288 return false
289 }
290
291 //Check if flow.table_id is covered by flow_mod.table_id
292 if mod.TableId != uint32(ofp.OfpTable_OFPTT_ALL) && flow.TableId != mod.TableId {
293 return false
294 }
295
296 //Check out_port
297 if (mod.OutPort&0x7fffffff) != uint32(ofp.OfpPortNo_OFPP_ANY) && !FlowHasOutPort(flow, mod.OutPort) {
298 return false
299 }
300
301 // Check out_group
302 if (mod.OutGroup&0x7fffffff) != uint32(ofp.OfpGroup_OFPG_ANY) && !FlowHasOutGroup(flow, mod.OutGroup) {
303 return false
304 }
305
306 //Priority is ignored
307
308 //Check match condition
309 //If the flow_mod match field is empty, that is a special case and indicates the flow entry matches
310 if (mod.Match == nil) || (mod.Match.OxmFields == nil) {
311 //If we got this far and the match is empty in the flow spec, than the flow matches
312 return true
313 } // TODO : implement the flow match analysis
314 return false
315
316}
317
318//FlowHasOutPort returns True if flow has a output command with the given out_port
319func FlowHasOutPort(flow *ofp.OfpFlowStats, outPort uint32) bool {
320 for _, instruction := range flow.Instructions {
321 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
322 if instruction.GetActions() == nil {
323 return false
324 }
325 for _, action := range instruction.GetActions().Actions {
326 if action.Type == ofp.OfpActionType_OFPAT_OUTPUT {
327 if (action.GetOutput() != nil) && (action.GetOutput().Port == outPort) {
328 return true
329 }
330 }
331
332 }
333 }
334 }
335 return false
336}
337
338//FlowHasOutGroup return True if flow has a output command with the given out_group
339func FlowHasOutGroup(flow *ofp.OfpFlowStats, groupID uint32) bool {
340 for _, instruction := range flow.Instructions {
341 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
342 if instruction.GetActions() == nil {
343 return false
344 }
345 for _, action := range instruction.GetActions().Actions {
346 if action.Type == ofp.OfpActionType_OFPAT_GROUP {
347 if (action.GetGroup() != nil) && (action.GetGroup().GroupId == groupID) {
348 return true
349 }
350 }
351
352 }
353 }
354 }
355 return false
356}
357
358//FindGroup returns index of group if found, else returns -1
359func FindGroup(groups []*ofp.OfpGroupEntry, groupId uint32) int {
360 for idx, group := range groups {
361 if group.Desc.GroupId == groupId {
362 return idx
363 }
364 }
365 return -1
366}
367
368func FlowsDeleteByGroupId(flows []*ofp.OfpFlowStats, groupId uint32) (bool, []*ofp.OfpFlowStats) {
369 toKeep := make([]*ofp.OfpFlowStats, 0)
370
371 for _, f := range flows {
372 if !FlowHasOutGroup(f, groupId) {
373 toKeep = append(toKeep, f)
374 }
375 }
376 return len(toKeep) < len(flows), toKeep
377}