blob: c778aa51dc9e1c89654f92e19c46eb7b46bf5a83 [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"
yasin sapli5458a1c2021-06-14 22:24:38 +000025 fu "github.com/opencord/voltha-lib-go/v5/pkg/flows"
26 "github.com/opencord/voltha-lib-go/v5/pkg/log"
Maninderdfadc982020-10-28 14:04:33 +053027 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 {
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() {
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)
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 }
Esin Karaman7eab1b92020-07-01 11:40:39 +0000166 //add groups to deviceRules
167 for _, groupEntry := range affectedGroups {
168 fg := fu.NewFlowsAndGroups()
169 fg.AddGroup(groupEntry)
170 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
171 }
172 logger.Debugw(ctx, "rules", log.Fields{"rules": deviceRules.String()})
173
174 // delete groups and related flows, if any
Gamze Abakafac8c192021-06-28 12:04:32 +0000175 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &ofp.OfpFlowMod{})
Esin Karaman7eab1b92020-07-01 11:40:39 +0000176
177 // Wait for completion
178 go func() {
179 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000180 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logical-device-id": agent.logicalDeviceID, "errors": res})
Himani Chawlab4c25912020-11-12 17:16:38 +0530181 context := make(map[string]string)
182 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
Himani Chawla03510772021-02-17 12:48:49 +0530183 context["group-id"] = fmt.Sprintf("%v", groupMod.GroupId)
184 context["logical-device-id"] = agent.logicalDeviceID
185 if deviceRules != nil {
186 context["device-rules"] = deviceRules.String()
187 }
Himani Chawla606a4f02021-03-23 19:45:58 +0530188 agent.ldeviceMgr.SendRPCEvent(ctx,
Himani Chawlab4c25912020-11-12 17:16:38 +0530189 agent.logicalDeviceID, "failed-to-update-device-flows-groups", context, "RPC_ERROR_RAISE_EVENT",
Himani Chawla606a4f02021-03-23 19:45:58 +0530190 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Esin Karaman7eab1b92020-07-01 11:40:39 +0000191 //TODO: Revert flow changes
192 }
193 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400194 return nil
195}
196
197func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530198 logger.Debug(ctx, "group-modify")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400199 if groupMod == nil {
200 return nil
201 }
202
203 groupID := groupMod.GroupId
Kent Hagerman433a31a2020-05-20 19:04:48 -0400204
khenaidoo7585a962021-06-10 16:15:38 -0400205 groupHandle, have := agent.groupCache.Lock(groupID)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400206 if !have {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400207 return fmt.Errorf("group-absent:%d", groupID)
208 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400209 defer groupHandle.Unlock()
210
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400211 //replace existing group entry with new group definition
212 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
213 deviceRules := fu.NewDeviceRules()
214 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
215 fg := fu.NewFlowsAndGroups()
216 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
217 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
218
Rohan Agrawal31f21802020-06-12 05:38:46 +0000219 logger.Debugw(ctx, "rules", log.Fields{"rules-for-group-modify": deviceRules.String()})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400220
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400221 //update KV
Kent Hagerman433a31a2020-05-20 19:04:48 -0400222 if err := groupHandle.Update(ctx, groupEntry); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530223 logger.Errorw(ctx, "cannot-update-logical-group", log.Fields{"logical-device-id": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400224 return err
225 }
226
227 // Update the devices
Rohan Agrawal31f21802020-06-12 05:38:46 +0000228 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400229
230 // Wait for completion
231 go func() {
232 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000233 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logical-device-id": agent.logicalDeviceID, "errors": res})
Himani Chawlab4c25912020-11-12 17:16:38 +0530234 context := make(map[string]string)
235 context["rpc"] = coreutils.GetRPCMetadataFromContext(ctx)
Himani Chawla03510772021-02-17 12:48:49 +0530236 context["group-id"] = fmt.Sprintf("%v", groupMod.GroupId)
237 context["logical-device-id"] = agent.logicalDeviceID
238 if deviceRules != nil {
239 context["device-rules"] = deviceRules.String()
240 }
Himani Chawla606a4f02021-03-23 19:45:58 +0530241 agent.ldeviceMgr.SendRPCEvent(ctx,
Himani Chawlab4c25912020-11-12 17:16:38 +0530242 agent.logicalDeviceID, "failed-to-update-device-flows-groups", context, "RPC_ERROR_RAISE_EVENT",
Himani Chawla606a4f02021-03-23 19:45:58 +0530243 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400244 //TODO: Revert flow changes
245 }
246 }()
247 return nil
248}