blob: bf31bc9c96c16e728acb6f6b883056ece51f2ea7 [file] [log] [blame]
Kent Hagerman3136fbd2020-05-14 10:30:45 -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
17package device
18
19import (
20 "context"
21 "fmt"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040022
23 coreutils "github.com/opencord/voltha-go/rw_core/utils"
24 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"
28 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
30)
31
Kent Hagerman433a31a2020-05-20 19:04:48 -040032// listLogicalDeviceGroups returns logical device flow groups
33func (agent *LogicalAgent) listLogicalDeviceGroups() map[uint32]*ofp.OfpGroupEntry {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040034 groupIDs := agent.groupLoader.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -040035 groups := make(map[uint32]*ofp.OfpGroupEntry, len(groupIDs))
36 for groupID := range groupIDs {
37 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
38 groups[groupID] = groupHandle.GetReadOnly()
39 groupHandle.Unlock()
40 }
41 }
42 return groups
43}
44
Kent Hagerman3136fbd2020-05-14 10:30:45 -040045//updateGroupTable updates the group table of that logical device
46func (agent *LogicalAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +000047 logger.Debug(ctx, "updateGroupTable")
Kent Hagerman3136fbd2020-05-14 10:30:45 -040048 if groupMod == nil {
49 return nil
50 }
51
Kent Hagerman3136fbd2020-05-14 10:30:45 -040052 switch groupMod.GetCommand() {
53 case ofp.OfpGroupModCommand_OFPGC_ADD:
54 return agent.groupAdd(ctx, groupMod)
55 case ofp.OfpGroupModCommand_OFPGC_DELETE:
56 return agent.groupDelete(ctx, groupMod)
57 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
58 return agent.groupModify(ctx, groupMod)
59 }
60 return status.Errorf(codes.Internal, "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
61}
62
63func (agent *LogicalAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
64 if groupMod == nil {
65 return nil
66 }
Rohan Agrawal31f21802020-06-12 05:38:46 +000067 logger.Debugw(ctx, "groupAdd", log.Fields{"GroupId": groupMod.GroupId})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040068
69 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
Kent Hagerman433a31a2020-05-20 19:04:48 -040070
71 groupHandle, created, err := agent.groupLoader.LockOrCreate(ctx, groupEntry)
72 if err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -040073 return err
74 }
Kent Hagerman433a31a2020-05-20 19:04:48 -040075 groupHandle.Unlock()
76
77 if !created {
78 return fmt.Errorf("group %d already exists", groupMod.GroupId)
79 }
80
Kent Hagerman3136fbd2020-05-14 10:30:45 -040081 fg := fu.NewFlowsAndGroups()
Kent Hagerman433a31a2020-05-20 19:04:48 -040082 fg.AddGroup(groupEntry)
83 deviceRules := fu.NewDeviceRules()
Kent Hagerman3136fbd2020-05-14 10:30:45 -040084 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
85
Rohan Agrawal31f21802020-06-12 05:38:46 +000086 logger.Debugw(ctx, "rules", log.Fields{"rules for group-add": deviceRules.String()})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040087
88 // Update the devices
Rohan Agrawal31f21802020-06-12 05:38:46 +000089 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040090
91 // Wait for completion
92 go func() {
93 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +000094 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040095 //TODO: Revert flow changes
96 }
97 }()
98 return nil
99}
100
101func (agent *LogicalAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000102 logger.Debug(ctx, "groupDelete")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400103 if groupMod == nil {
104 return nil
105 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400106
Kent Hagerman433a31a2020-05-20 19:04:48 -0400107 affectedFlows := make(map[uint64]*ofp.OfpFlowStats)
108 affectedGroups := make(map[uint32]*ofp.OfpGroupEntry)
109 var groupsChanged bool
110
111 toDelete := map[uint32]struct{}{groupMod.GroupId: {}}
112 if groupMod.GroupId == uint32(ofp.OfpGroup_OFPG_ALL) {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400113 toDelete = agent.groupLoader.ListIDs()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400114 }
115
Kent Hagerman433a31a2020-05-20 19:04:48 -0400116 for groupID := range toDelete {
117 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
Girish Gowdra4c4face2020-06-08 16:51:09 -0700118 affectedGroups[groupID] = groupHandle.GetReadOnly()
Kent Hagerman433a31a2020-05-20 19:04:48 -0400119 if err := groupHandle.Delete(ctx); err != nil {
120 return err
121 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400122 groupHandle.Unlock()
123
124 //TODO: this is another case where ordering guarantees are not being made,
125 // group deletion does not guarantee deletion of corresponding flows.
126 // an error while deleting flows can cause inconsistent state.
127 flows, err := agent.deleteFlowsHavingGroup(ctx, groupID)
128 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000129 logger.Errorw(ctx, "cannot-update-flow-for-group-delete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "groupID": groupID})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400130 return err
131 }
132 for flowID, flow := range flows {
133 affectedFlows[flowID] = flow
134 }
135 }
136 }
137 groupsChanged = true
138
139 //TODO: groupsChanged is always true here? use `len(affectedFlows)!=0` or `len(affectedGroups)!=0` instead?
140 if groupsChanged {
141 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, affectedFlows, affectedGroups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400142 if err != nil {
143 return err
144 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000145 logger.Debugw(ctx, "rules", log.Fields{"rules": deviceRules.String()})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400146
147 // Update the devices
Rohan Agrawal31f21802020-06-12 05:38:46 +0000148 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, nil)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400149
150 // Wait for completion
151 go func() {
152 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000153 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400154 //TODO: Revert flow changes
155 }
156 }()
157 }
158 return nil
159}
160
161func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000162 logger.Debug(ctx, "groupModify")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400163 if groupMod == nil {
164 return nil
165 }
166
167 groupID := groupMod.GroupId
Kent Hagerman433a31a2020-05-20 19:04:48 -0400168
169 groupHandle, have := agent.groupLoader.Lock(groupID)
170 if !have {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400171 return fmt.Errorf("group-absent:%d", groupID)
172 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400173 defer groupHandle.Unlock()
174
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400175 //replace existing group entry with new group definition
176 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
177 deviceRules := fu.NewDeviceRules()
178 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
179 fg := fu.NewFlowsAndGroups()
180 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
181 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
182
Rohan Agrawal31f21802020-06-12 05:38:46 +0000183 logger.Debugw(ctx, "rules", log.Fields{"rules-for-group-modify": deviceRules.String()})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400184
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400185 //update KV
Kent Hagerman433a31a2020-05-20 19:04:48 -0400186 if err := groupHandle.Update(ctx, groupEntry); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000187 logger.Errorw(ctx, "Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400188 return err
189 }
190
191 // Update the devices
Rohan Agrawal31f21802020-06-12 05:38:46 +0000192 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400193
194 // Wait for completion
195 go func() {
196 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000197 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400198 //TODO: Revert flow changes
199 }
200 }()
201 return nil
202}