blob: 9552b78d924d3d5a3d6026668431a81a9054f287 [file] [log] [blame]
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001/*
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 (
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070020 "context"
21 "strconv"
22
23 "github.com/gogo/protobuf/proto"
24 coreutils "github.com/opencord/voltha-go/rw_core/utils"
Maninderdfadc982020-10-28 14:04:33 +053025 "github.com/opencord/voltha-lib-go/v4/pkg/log"
26 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
27 "github.com/opencord/voltha-protos/v4/go/voltha"
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070028 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070030)
31
32// listDeviceGroups returns logical device flow groups
33func (agent *Agent) listDeviceGroups() map[uint32]*ofp.OfpGroupEntry {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040034 groupIDs := agent.groupLoader.ListIDs()
Mahir Gunyel03de0d32020-06-03 01:36:59 -070035 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}
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070044
45func (agent *Agent) addGroupsToAdapter(ctx context.Context, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +000046 logger.Debugw(ctx, "add-groups-to-adapters", log.Fields{"device-id": agent.deviceID, "groups": newGroups, "flow-metadata": flowMetadata})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070047
48 if (len(newGroups)) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +000049 logger.Debugw(ctx, "nothing-to-update", log.Fields{"device-id": agent.deviceID, "groups": newGroups})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070050 return coreutils.DoneResponse(), nil
51 }
52
Kent Hagermancba2f302020-07-28 13:37:36 -040053 device, err := agent.getDeviceReadOnly(ctx)
54 if err != nil {
55 return coreutils.DoneResponse(), status.Errorf(codes.Aborted, "%s", err)
56 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070057 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
58 if err != nil {
59 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
60 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070061
62 groupsToAdd := make([]*ofp.OfpGroupEntry, 0)
63 groupsToDelete := make([]*ofp.OfpGroupEntry, 0)
64 for _, group := range newGroups {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070065 groupHandle, created, err := agent.groupLoader.LockOrCreate(ctx, group)
66 if err != nil {
67 return coreutils.DoneResponse(), err
68 }
69
70 if created {
71 groupsToAdd = append(groupsToAdd, group)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070072 } else {
73 groupToChange := groupHandle.GetReadOnly()
74 if !proto.Equal(groupToChange, group) {
75 //Group needs to be updated.
76 if err := groupHandle.Update(ctx, group); err != nil {
77 groupHandle.Unlock()
78 return coreutils.DoneResponse(), status.Errorf(codes.Internal, "failure-updating-group-%s-to-device-%s", strconv.Itoa(int(group.Desc.GroupId)), agent.deviceID)
79 }
80 groupsToDelete = append(groupsToDelete, groupToChange)
81 groupsToAdd = append(groupsToAdd, group)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070082 } else {
83 //No need to change the group. It is already exist.
Himani Chawlab4c25912020-11-12 17:16:38 +053084 logger.Debugw(ctx, "no-need-to-change-already-existing-group", log.Fields{"device-id": agent.deviceID, "group": newGroups, "flow-metadata": flowMetadata})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070085 }
86 }
87
88 groupHandle.Unlock()
89 }
90 // Sanity check
91 if (len(groupsToAdd)) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +000092 logger.Debugw(ctx, "no-groups-to-update", log.Fields{"device-id": agent.deviceID, "groups": newGroups})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070093 return coreutils.DoneResponse(), nil
94 }
95
96 // Send update to adapters
Rohan Agrawalcf12f202020-08-03 04:42:01 +000097 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +053098 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
99
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700100 response := coreutils.NewResponse()
101 if !dType.AcceptsAddRemoveFlowUpdates {
Kent Hagermana7c9d792020-07-16 17:39:01 -0400102 updatedAllGroups := agent.listDeviceGroups()
103 rpcResponse, err := agent.adapterProxy.UpdateFlowsBulk(subCtx, device, nil, updatedAllGroups, flowMetadata)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700104 if err != nil {
105 cancel()
106 return coreutils.DoneResponse(), err
107 }
108 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
109 } else {
110 flowChanges := &ofp.FlowChanges{
111 ToAdd: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
112 ToRemove: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
113 }
114 groupChanges := &ofp.FlowGroupChanges{
115 ToAdd: &voltha.FlowGroups{Items: groupsToAdd},
116 ToRemove: &voltha.FlowGroups{Items: groupsToDelete},
117 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
118 }
119 rpcResponse, err := agent.adapterProxy.UpdateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
120 if err != nil {
121 cancel()
122 return coreutils.DoneResponse(), err
123 }
124 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
125 }
126 return response, nil
127}
128
129func (agent *Agent) deleteGroupsFromAdapter(ctx context.Context, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000130 logger.Debugw(ctx, "delete-groups-from-adapter", log.Fields{"device-id": agent.deviceID, "groups": groupsToDel})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700131
132 if (len(groupsToDel)) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000133 logger.Debugw(ctx, "nothing-to-delete", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700134 return coreutils.DoneResponse(), nil
135 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400136 device, err := agent.getDeviceReadOnly(ctx)
137 if err != nil {
138 return coreutils.DoneResponse(), status.Errorf(codes.Aborted, "%s", err)
139 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700140 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
141 if err != nil {
142 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
143 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700144
145 for _, group := range groupsToDel {
146 if groupHandle, have := agent.groupLoader.Lock(group.Desc.GroupId); have {
147 // Update the store and cache
148 if err := groupHandle.Delete(ctx); err != nil {
149 groupHandle.Unlock()
150 return coreutils.DoneResponse(), err
151 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700152 groupHandle.Unlock()
153 }
154 }
155
156 // Send update to adapters
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000157 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530158 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
159
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700160 response := coreutils.NewResponse()
161 if !dType.AcceptsAddRemoveFlowUpdates {
Kent Hagermana7c9d792020-07-16 17:39:01 -0400162 updatedAllGroups := agent.listDeviceGroups()
163 rpcResponse, err := agent.adapterProxy.UpdateFlowsBulk(subCtx, device, nil, updatedAllGroups, flowMetadata)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700164 if err != nil {
165 cancel()
166 return coreutils.DoneResponse(), err
167 }
168 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
169 } else {
170 flowChanges := &ofp.FlowChanges{
171 ToAdd: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
172 ToRemove: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
173 }
174 groupChanges := &ofp.FlowGroupChanges{
175 ToAdd: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
176 ToRemove: &voltha.FlowGroups{Items: groupsToDel},
177 ToUpdate: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
178 }
179 rpcResponse, err := agent.adapterProxy.UpdateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
180 if err != nil {
181 cancel()
182 return coreutils.DoneResponse(), err
183 }
184 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
185 }
186 return response, nil
187}
188
189func (agent *Agent) updateGroupsToAdapter(ctx context.Context, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) (coreutils.Response, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530190 logger.Debugw(ctx, "update-groups-to-adapter", log.Fields{"device-id": agent.deviceID, "groups": updatedGroups})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700191
192 if (len(updatedGroups)) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000193 logger.Debugw(ctx, "nothing-to-update", log.Fields{"device-id": agent.deviceID, "groups": updatedGroups})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700194 return coreutils.DoneResponse(), nil
195 }
196
Kent Hagermancba2f302020-07-28 13:37:36 -0400197 device, err := agent.getDeviceReadOnly(ctx)
198 if err != nil {
199 return coreutils.DoneResponse(), status.Errorf(codes.Aborted, "%s", err)
200 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700201 if device.OperStatus != voltha.OperStatus_ACTIVE || device.ConnectStatus != voltha.ConnectStatus_REACHABLE || device.AdminState != voltha.AdminState_ENABLED {
202 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "invalid device states-oper-%s-connect-%s-admin-%s", device.OperStatus, device.ConnectStatus, device.AdminState)
203 }
204 dType, err := agent.adapterMgr.GetDeviceType(ctx, &voltha.ID{Id: device.Type})
205 if err != nil {
206 return coreutils.DoneResponse(), status.Errorf(codes.FailedPrecondition, "non-existent-device-type-%s", device.Type)
207 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700208
Kent Hagermana7c9d792020-07-16 17:39:01 -0400209 groupsToUpdate := make([]*ofp.OfpGroupEntry, 0)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700210 for _, group := range updatedGroups {
211 if groupHandle, have := agent.groupLoader.Lock(group.Desc.GroupId); have {
212 // Update the store and cache
213 if err := groupHandle.Update(ctx, group); err != nil {
214 groupHandle.Unlock()
215 return coreutils.DoneResponse(), err
216 }
217 groupsToUpdate = append(groupsToUpdate, group)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700218 groupHandle.Unlock()
219 }
220 }
221
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000222 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530223 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
224
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700225 response := coreutils.NewResponse()
226 // Process bulk flow update differently than incremental update
227 if !dType.AcceptsAddRemoveFlowUpdates {
Kent Hagermana7c9d792020-07-16 17:39:01 -0400228 updatedAllGroups := agent.listDeviceGroups()
229 rpcResponse, err := agent.adapterProxy.UpdateFlowsBulk(subCtx, device, nil, updatedAllGroups, nil)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700230 if err != nil {
231 cancel()
232 return coreutils.DoneResponse(), err
233 }
234 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
235 } else {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000236 logger.Debugw(ctx, "updating-groups",
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700237 log.Fields{
238 "device-id": agent.deviceID,
239 "groups-to-update": groupsToUpdate,
240 })
241
242 // Sanity check
243 if (len(groupsToUpdate)) == 0 {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000244 logger.Debugw(ctx, "nothing-to-update", log.Fields{"device-id": agent.deviceID, "groups": groupsToUpdate})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700245 cancel()
246 return coreutils.DoneResponse(), nil
247 }
248
249 flowChanges := &ofp.FlowChanges{
250 ToAdd: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
251 ToRemove: &voltha.Flows{Items: []*ofp.OfpFlowStats{}},
252 }
253 groupChanges := &ofp.FlowGroupChanges{
254 ToAdd: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
255 ToRemove: &voltha.FlowGroups{Items: []*ofp.OfpGroupEntry{}},
256 ToUpdate: &voltha.FlowGroups{Items: groupsToUpdate},
257 }
258 rpcResponse, err := agent.adapterProxy.UpdateFlowsIncremental(subCtx, device, flowChanges, groupChanges, flowMetadata)
259 if err != nil {
260 cancel()
261 return coreutils.DoneResponse(), err
262 }
263 go agent.waitForAdapterFlowResponse(subCtx, cancel, rpcResponse, response)
264 }
265
266 return response, nil
267}