blob: b7bf1b6f5e997c8cf7a08325464a191336807e15 [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"
Himani Chawlab4c25912020-11-12 17:16:38 +053022 "time"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040023
24 coreutils "github.com/opencord/voltha-go/rw_core/utils"
Maninderdfadc982020-10-28 14:04:33 +053025 fu "github.com/opencord/voltha-lib-go/v4/pkg/flows"
26 "github.com/opencord/voltha-lib-go/v4/pkg/log"
27 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
28 "github.com/opencord/voltha-protos/v4/go/voltha"
Kent Hagerman3136fbd2020-05-14 10:30:45 -040029 "google.golang.org/grpc/codes"
30 "google.golang.org/grpc/status"
31)
32
Kent Hagerman433a31a2020-05-20 19:04:48 -040033// listLogicalDeviceGroups returns logical device flow groups
34func (agent *LogicalAgent) listLogicalDeviceGroups() map[uint32]*ofp.OfpGroupEntry {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040035 groupIDs := agent.groupLoader.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -040036 groups := make(map[uint32]*ofp.OfpGroupEntry, len(groupIDs))
37 for groupID := range groupIDs {
38 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
39 groups[groupID] = groupHandle.GetReadOnly()
40 groupHandle.Unlock()
41 }
42 }
43 return groups
44}
45
Kent Hagerman3136fbd2020-05-14 10:30:45 -040046//updateGroupTable updates the group table of that logical device
47func (agent *LogicalAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Himani Chawlab4c25912020-11-12 17:16:38 +053048 logger.Debug(ctx, "update-group-table")
Kent Hagerman3136fbd2020-05-14 10:30:45 -040049 if groupMod == nil {
50 return nil
51 }
52
Kent Hagerman3136fbd2020-05-14 10:30:45 -040053 switch groupMod.GetCommand() {
54 case ofp.OfpGroupModCommand_OFPGC_ADD:
55 return agent.groupAdd(ctx, groupMod)
56 case ofp.OfpGroupModCommand_OFPGC_DELETE:
57 return agent.groupDelete(ctx, groupMod)
58 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
59 return agent.groupModify(ctx, groupMod)
60 }
divyadesaicb8b59d2020-08-18 09:55:47 +000061 return status.Errorf(codes.Internal, "unhandled-command: logical-device-id:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
Kent Hagerman3136fbd2020-05-14 10:30:45 -040062}
63
64func (agent *LogicalAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
65 if groupMod == nil {
66 return nil
67 }
Himani Chawlab4c25912020-11-12 17:16:38 +053068 logger.Debugw(ctx, "group-add", log.Fields{"group-id": groupMod.GroupId})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040069
70 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
Kent Hagerman433a31a2020-05-20 19:04:48 -040071
72 groupHandle, created, err := agent.groupLoader.LockOrCreate(ctx, groupEntry)
73 if err != nil {
Kent Hagerman3136fbd2020-05-14 10:30:45 -040074 return err
75 }
Kent Hagerman433a31a2020-05-20 19:04:48 -040076 groupHandle.Unlock()
77
78 if !created {
79 return fmt.Errorf("group %d already exists", groupMod.GroupId)
80 }
81
Kent Hagerman3136fbd2020-05-14 10:30:45 -040082 fg := fu.NewFlowsAndGroups()
Kent Hagerman433a31a2020-05-20 19:04:48 -040083 fg.AddGroup(groupEntry)
84 deviceRules := fu.NewDeviceRules()
Kent Hagerman3136fbd2020-05-14 10:30:45 -040085 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
86
Himani Chawlab4c25912020-11-12 17:16:38 +053087 logger.Debugw(ctx, "rules", log.Fields{"rules-for-group-add": deviceRules.String()})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040088
89 // Update the devices
Rohan Agrawal31f21802020-06-12 05:38:46 +000090 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{})
Kent Hagerman3136fbd2020-05-14 10:30:45 -040091
92 // Wait for completion
93 go func() {
94 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +000095 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logical-device-id": agent.logicalDeviceID, "errors": res})
Himani Chawlab4c25912020-11-12 17:16:38 +053096 context := make(map[string]string)
97 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
98 context["group-id"] = string(groupMod.GroupId)
99 context["device-rules"] = deviceRules.String()
100 go agent.ldeviceMgr.SendRPCEvent(ctx,
101 agent.logicalDeviceID, "failed-to-update-device-flows-groups", context, "RPC_ERROR_RAISE_EVENT",
102 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400103 //TODO: Revert flow changes
104 }
105 }()
106 return nil
107}
108
109func (agent *LogicalAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530110 logger.Debugw(ctx, "group-delete", log.Fields{"group-mod": groupMod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400111 if groupMod == nil {
112 return nil
113 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400114
Kent Hagerman433a31a2020-05-20 19:04:48 -0400115 affectedFlows := make(map[uint64]*ofp.OfpFlowStats)
116 affectedGroups := make(map[uint32]*ofp.OfpGroupEntry)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400117
118 toDelete := map[uint32]struct{}{groupMod.GroupId: {}}
119 if groupMod.GroupId == uint32(ofp.OfpGroup_OFPG_ALL) {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400120 toDelete = agent.groupLoader.ListIDs()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400121 }
122
Kent Hagerman433a31a2020-05-20 19:04:48 -0400123 for groupID := range toDelete {
124 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
Girish Gowdra4c4face2020-06-08 16:51:09 -0700125 affectedGroups[groupID] = groupHandle.GetReadOnly()
Kent Hagerman433a31a2020-05-20 19:04:48 -0400126 if err := groupHandle.Delete(ctx); err != nil {
127 return err
128 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400129 groupHandle.Unlock()
130
131 //TODO: this is another case where ordering guarantees are not being made,
132 // group deletion does not guarantee deletion of corresponding flows.
133 // an error while deleting flows can cause inconsistent state.
134 flows, err := agent.deleteFlowsHavingGroup(ctx, groupID)
135 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000136 logger.Errorw(ctx, "cannot-update-flow-for-group-delete", log.Fields{"logical-device-id": agent.logicalDeviceID, "groupID": groupID})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400137 return err
138 }
139 for flowID, flow := range flows {
140 affectedFlows[flowID] = flow
141 }
142 }
143 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400144
Esin Karaman7eab1b92020-07-01 11:40:39 +0000145 if len(affectedGroups) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530146 logger.Debugw(ctx, "no-group-to-delete", log.Fields{"group-id": groupMod.GroupId})
Esin Karaman7eab1b92020-07-01 11:40:39 +0000147 return nil
148 }
149
150 var deviceRules *fu.DeviceRules
151 var err error
152
153 if len(affectedFlows) != 0 {
154 deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, affectedFlows, affectedGroups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400155 if err != nil {
156 return err
157 }
Esin Karaman7eab1b92020-07-01 11:40:39 +0000158 } else {
159 //no flow is affected, just remove the groups
160 deviceRules = fu.NewDeviceRules()
161 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400162 }
Esin Karaman7eab1b92020-07-01 11:40:39 +0000163 //add groups to deviceRules
164 for _, groupEntry := range affectedGroups {
165 fg := fu.NewFlowsAndGroups()
166 fg.AddGroup(groupEntry)
167 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
168 }
169 logger.Debugw(ctx, "rules", log.Fields{"rules": deviceRules.String()})
170
171 // delete groups and related flows, if any
172 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &voltha.FlowMetadata{}, &ofp.OfpFlowMod{})
173
174 // Wait for completion
175 go func() {
176 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000177 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logical-device-id": agent.logicalDeviceID, "errors": res})
Himani Chawlab4c25912020-11-12 17:16:38 +0530178 context := make(map[string]string)
179 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
180 context["group-id"] = string(groupMod.GroupId)
181 context["device-rules"] = deviceRules.String()
182 go agent.ldeviceMgr.SendRPCEvent(ctx,
183 agent.logicalDeviceID, "failed-to-update-device-flows-groups", context, "RPC_ERROR_RAISE_EVENT",
184 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
Esin Karaman7eab1b92020-07-01 11:40:39 +0000185 //TODO: Revert flow changes
186 }
187 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400188 return nil
189}
190
191func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530192 logger.Debug(ctx, "group-modify")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400193 if groupMod == nil {
194 return nil
195 }
196
197 groupID := groupMod.GroupId
Kent Hagerman433a31a2020-05-20 19:04:48 -0400198
199 groupHandle, have := agent.groupLoader.Lock(groupID)
200 if !have {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400201 return fmt.Errorf("group-absent:%d", groupID)
202 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400203 defer groupHandle.Unlock()
204
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400205 //replace existing group entry with new group definition
206 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
207 deviceRules := fu.NewDeviceRules()
208 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
209 fg := fu.NewFlowsAndGroups()
210 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
211 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
212
Rohan Agrawal31f21802020-06-12 05:38:46 +0000213 logger.Debugw(ctx, "rules", log.Fields{"rules-for-group-modify": deviceRules.String()})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400214
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400215 //update KV
Kent Hagerman433a31a2020-05-20 19:04:48 -0400216 if err := groupHandle.Update(ctx, groupEntry); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530217 logger.Errorw(ctx, "cannot-update-logical-group", log.Fields{"logical-device-id": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400218 return err
219 }
220
221 // Update the devices
Rohan Agrawal31f21802020-06-12 05:38:46 +0000222 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400223
224 // Wait for completion
225 go func() {
226 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000227 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logical-device-id": agent.logicalDeviceID, "errors": res})
Himani Chawlab4c25912020-11-12 17:16:38 +0530228 context := make(map[string]string)
229 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
230 context["group-id"] = string(groupMod.GroupId)
231 context["device-rules"] = deviceRules.String()
232 go agent.ldeviceMgr.SendRPCEvent(ctx,
233 agent.logicalDeviceID, "failed-to-update-device-flows-groups", context, "RPC_ERROR_RAISE_EVENT",
234 voltha.EventCategory_COMMUNICATION, nil, time.Now().UnixNano())
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400235 //TODO: Revert flow changes
236 }
237 }()
238 return nil
239}