blob: c2c9287a5f6905dd99373536b6ee76348a46f8bd [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"
William Kurkiandaa6bb22019-03-07 12:26:28 -050022 ofp "github.com/opencord/voltha-protos/go/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()
manikkaraj k6c9689d2019-05-09 12:59:52 -0400174 if dr != nil {
175 for key, val := range dr.Rules {
176 if val != nil {
177 copyDR.Rules[key] = val.Copy()
178 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400179 }
khenaidoo89b0e942018-10-21 21:11:33 -0400180 }
181 return copyDR
182}
183
khenaidoo19d7b632018-10-30 10:49:50 -0400184func (dr *DeviceRules) ClearFlows(deviceId string) {
185 if _, exist := dr.Rules[deviceId]; exist {
186 dr.Rules[deviceId].Flows = ordered_map.NewOrderedMap()
187 }
188}
189
khenaidoo2c6a0992019-04-29 13:46:56 -0400190func (dr *DeviceRules) FilterRules(deviceIds map[string]string) *DeviceRules {
191 filteredDR := NewDeviceRules()
192 for key, val := range dr.Rules {
193 if _, exist := deviceIds[key]; exist {
194 filteredDR.Rules[key] = val.Copy()
195 }
196 }
197 return filteredDR
198}
199
khenaidoo19d7b632018-10-30 10:49:50 -0400200func (dr *DeviceRules) AddFlow(deviceId string, flow *ofp.OfpFlowStats) {
201 if _, exist := dr.Rules[deviceId]; !exist {
202 dr.Rules[deviceId] = NewFlowsAndGroups()
203 }
204 dr.Rules[deviceId].AddFlow(flow)
205}
206
207func (dr *DeviceRules) GetRules() map[string]*FlowsAndGroups {
208 return dr.Rules
209}
210
khenaidoo89b0e942018-10-21 21:11:33 -0400211func (dr *DeviceRules) String() string {
212 var buffer bytes.Buffer
213 for key, value := range dr.Rules {
214 buffer.WriteString("DeviceId:")
215 buffer.WriteString(key)
216 buffer.WriteString(value.String())
217 buffer.WriteString("\n\n")
218 }
219 return buffer.String()
220}
221
222func (dr *DeviceRules) AddFlowsAndGroup(deviceId string, fg *FlowsAndGroups) {
khenaidood20a5852018-10-22 22:09:55 -0400223 if _, ok := dr.Rules[deviceId]; !ok {
224 dr.Rules[deviceId] = NewFlowsAndGroups()
225 }
khenaidoo89b0e942018-10-21 21:11:33 -0400226 dr.Rules[deviceId] = fg
227}
khenaidood20a5852018-10-22 22:09:55 -0400228
229// CreateEntryIfNotExist creates a new deviceId in the Map if it does not exist and assigns an
230// empty FlowsAndGroups to it. Otherwise, it does nothing.
231func (dr *DeviceRules) CreateEntryIfNotExist(deviceId string) {
232 if _, ok := dr.Rules[deviceId]; !ok {
233 dr.Rules[deviceId] = NewFlowsAndGroups()
234 }
235}
khenaidoo19d7b632018-10-30 10:49:50 -0400236
237/*
238 * Common flow routines
239 */
240
241//FindOverlappingFlows return a list of overlapping flow(s) where mod is the flow request
242func FindOverlappingFlows(flows []*ofp.OfpFlowStats, mod *ofp.OfpFlowMod) []*ofp.OfpFlowStats {
243 return nil //TODO - complete implementation
244}
245
246// FindFlowById returns the index of the flow in the flows array if present. Otherwise, it returns -1
247func FindFlowById(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
248 for idx, f := range flows {
249 if flow.Id == f.Id {
250 return idx
251 }
252 }
253 return -1
254}
255
256// FindFlows returns the index in flows where flow if present. Otherwise, it returns -1
257func FindFlows(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
258 for idx, f := range flows {
259 if FlowMatch(f, flow) {
260 return idx
261 }
262 }
263 return -1
264}
265
266//FlowMatch returns true if two flows matches on the following flow attributes:
267//TableId, Priority, Flags, Cookie, Match
268func FlowMatch(f1 *ofp.OfpFlowStats, f2 *ofp.OfpFlowStats) bool {
269 keysMatter := []string{"TableId", "Priority", "Flags", "Cookie", "Match"}
270 for _, key := range keysMatter {
271 switch key {
272 case "TableId":
273 if f1.TableId != f2.TableId {
274 return false
275 }
276 case "Priority":
277 if f1.Priority != f2.Priority {
278 return false
279 }
280 case "Flags":
281 if f1.Flags != f2.Flags {
282 return false
283 }
284 case "Cookie":
285 if f1.Cookie != f2.Cookie {
286 return false
287 }
288 case "Match":
289 if strings.Compare(f1.Match.String(), f2.Match.String()) != 0 {
290 return false
291 }
292 }
293 }
294 return true
295}
296
297//FlowMatchesMod returns True if given flow is "covered" by the wildcard flow_mod, taking into consideration of
298//both exact matches as well as masks-based match fields if any. Otherwise return False
299func FlowMatchesMod(flow *ofp.OfpFlowStats, mod *ofp.OfpFlowMod) bool {
300 //Check if flow.cookie is covered by mod.cookie and mod.cookie_mask
301 if (flow.Cookie & mod.CookieMask) != (mod.Cookie & mod.CookieMask) {
302 return false
303 }
304
305 //Check if flow.table_id is covered by flow_mod.table_id
306 if mod.TableId != uint32(ofp.OfpTable_OFPTT_ALL) && flow.TableId != mod.TableId {
307 return false
308 }
309
310 //Check out_port
311 if (mod.OutPort&0x7fffffff) != uint32(ofp.OfpPortNo_OFPP_ANY) && !FlowHasOutPort(flow, mod.OutPort) {
312 return false
313 }
314
315 // Check out_group
316 if (mod.OutGroup&0x7fffffff) != uint32(ofp.OfpGroup_OFPG_ANY) && !FlowHasOutGroup(flow, mod.OutGroup) {
317 return false
318 }
319
320 //Priority is ignored
321
322 //Check match condition
323 //If the flow_mod match field is empty, that is a special case and indicates the flow entry matches
324 if (mod.Match == nil) || (mod.Match.OxmFields == nil) {
325 //If we got this far and the match is empty in the flow spec, than the flow matches
326 return true
327 } // TODO : implement the flow match analysis
328 return false
329
330}
331
332//FlowHasOutPort returns True if flow has a output command with the given out_port
333func FlowHasOutPort(flow *ofp.OfpFlowStats, outPort uint32) bool {
334 for _, instruction := range flow.Instructions {
335 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
336 if instruction.GetActions() == nil {
337 return false
338 }
339 for _, action := range instruction.GetActions().Actions {
340 if action.Type == ofp.OfpActionType_OFPAT_OUTPUT {
341 if (action.GetOutput() != nil) && (action.GetOutput().Port == outPort) {
342 return true
343 }
344 }
345
346 }
347 }
348 }
349 return false
350}
351
352//FlowHasOutGroup return True if flow has a output command with the given out_group
353func FlowHasOutGroup(flow *ofp.OfpFlowStats, groupID uint32) bool {
354 for _, instruction := range flow.Instructions {
355 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
356 if instruction.GetActions() == nil {
357 return false
358 }
359 for _, action := range instruction.GetActions().Actions {
360 if action.Type == ofp.OfpActionType_OFPAT_GROUP {
361 if (action.GetGroup() != nil) && (action.GetGroup().GroupId == groupID) {
362 return true
363 }
364 }
365
366 }
367 }
368 }
369 return false
370}
371
372//FindGroup returns index of group if found, else returns -1
373func FindGroup(groups []*ofp.OfpGroupEntry, groupId uint32) int {
374 for idx, group := range groups {
375 if group.Desc.GroupId == groupId {
376 return idx
377 }
378 }
379 return -1
380}
381
382func FlowsDeleteByGroupId(flows []*ofp.OfpFlowStats, groupId uint32) (bool, []*ofp.OfpFlowStats) {
383 toKeep := make([]*ofp.OfpFlowStats, 0)
384
385 for _, f := range flows {
386 if !FlowHasOutGroup(f, groupId) {
387 toKeep = append(toKeep, f)
388 }
389 }
390 return len(toKeep) < len(flows), toKeep
391}