blob: 261b0a5232f7b1a1edd5965c904bfb84c44f87de [file] [log] [blame]
Kent Hagerman3136fbd2020-05-14 10:30:45 -04001/*
Joey Armstrong5f51f2e2023-01-17 17:06:26 -05002 * Copyright 2018-2023 Open Networking Foundation (ONF) and the ONF Contributors
Kent Hagerman3136fbd2020-05-14 10:30:45 -04003
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"
khenaidood948f772021-08-11 17:49:24 -040025 fu "github.com/opencord/voltha-lib-go/v7/pkg/flows"
26 "github.com/opencord/voltha-lib-go/v7/pkg/log"
27 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
28 "github.com/opencord/voltha-protos/v5/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 {
khenaidoo7585a962021-06-10 16:15:38 -040035 groupIDs := agent.groupCache.ListIDs()
Kent Hagerman433a31a2020-05-20 19:04:48 -040036 groups := make(map[uint32]*ofp.OfpGroupEntry, len(groupIDs))
37 for groupID := range groupIDs {
khenaidoo7585a962021-06-10 16:15:38 -040038 if groupHandle, have := agent.groupCache.Lock(groupID); have {
Kent Hagerman433a31a2020-05-20 19:04:48 -040039 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
khenaidoo7585a962021-06-10 16:15:38 -040072 groupHandle, created, err := agent.groupCache.LockOrCreate(ctx, groupEntry)
Kent Hagerman433a31a2020-05-20 19:04:48 -040073 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
Gamze Abakafac8c192021-06-28 12:04:32 +000090 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules)
Kent Hagerman3136fbd2020-05-14 10:30:45 -040091
92 // Wait for completion
93 go func() {
khenaidood948f772021-08-11 17:49:24 -040094 if res := coreutils.WaitForNilOrErrorResponses(agent.internalTimeout, 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)
Himani Chawla03510772021-02-17 12:48:49 +053098 context["logical-device-id"] = agent.logicalDeviceID
99 context["group-id"] = fmt.Sprintf("%v", groupMod.GroupId)
100 if deviceRules != nil {
101 context["device-rules"] = deviceRules.String()
102 }
Himani Chawla606a4f02021-03-23 19:45:58 +0530103 agent.ldeviceMgr.SendRPCEvent(ctx,
Himani Chawlab4c25912020-11-12 17:16:38 +0530104 agent.logicalDeviceID, "failed-to-update-device-flows-groups", context, "RPC_ERROR_RAISE_EVENT",
Himani Chawla606a4f02021-03-23 19:45:58 +0530105 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400106 //TODO: Revert flow changes
107 }
108 }()
109 return nil
110}
111
112func (agent *LogicalAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530113 logger.Debugw(ctx, "group-delete", log.Fields{"group-mod": groupMod})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400114 if groupMod == nil {
115 return nil
116 }
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400117
Kent Hagerman433a31a2020-05-20 19:04:48 -0400118 affectedFlows := make(map[uint64]*ofp.OfpFlowStats)
119 affectedGroups := make(map[uint32]*ofp.OfpGroupEntry)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400120
121 toDelete := map[uint32]struct{}{groupMod.GroupId: {}}
122 if groupMod.GroupId == uint32(ofp.OfpGroup_OFPG_ALL) {
khenaidoo7585a962021-06-10 16:15:38 -0400123 toDelete = agent.groupCache.ListIDs()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400124 }
125
Kent Hagerman433a31a2020-05-20 19:04:48 -0400126 for groupID := range toDelete {
khenaidoo7585a962021-06-10 16:15:38 -0400127 if groupHandle, have := agent.groupCache.Lock(groupID); have {
Girish Gowdra4c4face2020-06-08 16:51:09 -0700128 affectedGroups[groupID] = groupHandle.GetReadOnly()
Kent Hagerman433a31a2020-05-20 19:04:48 -0400129 if err := groupHandle.Delete(ctx); err != nil {
130 return err
131 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400132 groupHandle.Unlock()
133
134 //TODO: this is another case where ordering guarantees are not being made,
135 // group deletion does not guarantee deletion of corresponding flows.
136 // an error while deleting flows can cause inconsistent state.
137 flows, err := agent.deleteFlowsHavingGroup(ctx, groupID)
138 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000139 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 -0400140 return err
141 }
142 for flowID, flow := range flows {
143 affectedFlows[flowID] = flow
144 }
145 }
146 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400147
Esin Karaman7eab1b92020-07-01 11:40:39 +0000148 if len(affectedGroups) == 0 {
Himani Chawlab4c25912020-11-12 17:16:38 +0530149 logger.Debugw(ctx, "no-group-to-delete", log.Fields{"group-id": groupMod.GroupId})
Esin Karaman7eab1b92020-07-01 11:40:39 +0000150 return nil
151 }
152
153 var deviceRules *fu.DeviceRules
154 var err error
155
156 if len(affectedFlows) != 0 {
157 deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, affectedFlows, affectedGroups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400158 if err != nil {
159 return err
160 }
Esin Karaman7eab1b92020-07-01 11:40:39 +0000161 } else {
162 //no flow is affected, just remove the groups
163 deviceRules = fu.NewDeviceRules()
164 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400165 }
khenaidood948f772021-08-11 17:49:24 -0400166
Esin Karaman7eab1b92020-07-01 11:40:39 +0000167 //add groups to deviceRules
168 for _, groupEntry := range affectedGroups {
169 fg := fu.NewFlowsAndGroups()
170 fg.AddGroup(groupEntry)
171 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
172 }
173 logger.Debugw(ctx, "rules", log.Fields{"rules": deviceRules.String()})
174
khenaidood948f772021-08-11 17:49:24 -0400175 if err := agent.deviceMgr.canMultipleAdapterRequestProceed(ctx, deviceRules.Keys()); err != nil {
176 logger.Warnw(ctx, "adapters-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
177 return err
178 }
179
Esin Karaman7eab1b92020-07-01 11:40:39 +0000180 // delete groups and related flows, if any
Gamze Abakafac8c192021-06-28 12:04:32 +0000181 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &ofp.OfpFlowMod{})
Esin Karaman7eab1b92020-07-01 11:40:39 +0000182
183 // Wait for completion
184 go func() {
khenaidood948f772021-08-11 17:49:24 -0400185 if res := coreutils.WaitForNilOrErrorResponses(agent.internalTimeout, respChnls...); res != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000186 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logical-device-id": agent.logicalDeviceID, "errors": res})
Himani Chawlab4c25912020-11-12 17:16:38 +0530187 context := make(map[string]string)
188 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
Himani Chawla03510772021-02-17 12:48:49 +0530189 context["group-id"] = fmt.Sprintf("%v", groupMod.GroupId)
190 context["logical-device-id"] = agent.logicalDeviceID
191 if deviceRules != nil {
192 context["device-rules"] = deviceRules.String()
193 }
Himani Chawla606a4f02021-03-23 19:45:58 +0530194 agent.ldeviceMgr.SendRPCEvent(ctx,
Himani Chawlab4c25912020-11-12 17:16:38 +0530195 agent.logicalDeviceID, "failed-to-update-device-flows-groups", context, "RPC_ERROR_RAISE_EVENT",
Himani Chawla606a4f02021-03-23 19:45:58 +0530196 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Esin Karaman7eab1b92020-07-01 11:40:39 +0000197 //TODO: Revert flow changes
198 }
199 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400200 return nil
201}
202
203func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530204 logger.Debug(ctx, "group-modify")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400205 if groupMod == nil {
206 return nil
207 }
208
209 groupID := groupMod.GroupId
Kent Hagerman433a31a2020-05-20 19:04:48 -0400210
khenaidoo7585a962021-06-10 16:15:38 -0400211 groupHandle, have := agent.groupCache.Lock(groupID)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400212 if !have {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400213 return fmt.Errorf("group-absent:%d", groupID)
214 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400215 defer groupHandle.Unlock()
216
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400217 //replace existing group entry with new group definition
218 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
219 deviceRules := fu.NewDeviceRules()
220 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
221 fg := fu.NewFlowsAndGroups()
222 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
223 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
224
Rohan Agrawal31f21802020-06-12 05:38:46 +0000225 logger.Debugw(ctx, "rules", log.Fields{"rules-for-group-modify": deviceRules.String()})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400226
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400227 //update KV
Kent Hagerman433a31a2020-05-20 19:04:48 -0400228 if err := groupHandle.Update(ctx, groupEntry); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530229 logger.Errorw(ctx, "cannot-update-logical-group", log.Fields{"logical-device-id": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400230 return err
231 }
232
233 // Update the devices
khenaidoo9beaaf12021-10-19 17:32:01 -0400234 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &ofp.FlowMetadata{})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400235
236 // Wait for completion
237 go func() {
khenaidood948f772021-08-11 17:49:24 -0400238 if res := coreutils.WaitForNilOrErrorResponses(agent.internalTimeout, respChnls...); res != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000239 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logical-device-id": agent.logicalDeviceID, "errors": res})
Himani Chawlab4c25912020-11-12 17:16:38 +0530240 context := make(map[string]string)
241 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
Himani Chawla03510772021-02-17 12:48:49 +0530242 context["group-id"] = fmt.Sprintf("%v", groupMod.GroupId)
243 context["logical-device-id"] = agent.logicalDeviceID
244 if deviceRules != nil {
245 context["device-rules"] = deviceRules.String()
246 }
Himani Chawla606a4f02021-03-23 19:45:58 +0530247 agent.ldeviceMgr.SendRPCEvent(ctx,
Himani Chawlab4c25912020-11-12 17:16:38 +0530248 agent.logicalDeviceID, "failed-to-update-device-flows-groups", context, "RPC_ERROR_RAISE_EVENT",
Himani Chawla606a4f02021-03-23 19:45:58 +0530249 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400250 //TODO: Revert flow changes
251 }
252 }()
253 return nil
254}