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