blob: 011b1962b3c99b67714367142eed36d42300e3c7 [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 }
divyadesaicb8b59d2020-08-18 09:55:47 +000060 return status.Errorf(codes.Internal, "unhandled-command: logical-device-id:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
Kent Hagerman3136fbd2020-05-14 10:30:45 -040061}
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 {
divyadesaicb8b59d2020-08-18 09:55:47 +000094 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logical-device-id": 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 {
Esin Karaman7eab1b92020-07-01 11:40:39 +0000102 logger.Debugw(ctx, "groupDelete", log.Fields{"groupMod": groupMod})
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)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400109
110 toDelete := map[uint32]struct{}{groupMod.GroupId: {}}
111 if groupMod.GroupId == uint32(ofp.OfpGroup_OFPG_ALL) {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400112 toDelete = agent.groupLoader.ListIDs()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400113 }
114
Kent Hagerman433a31a2020-05-20 19:04:48 -0400115 for groupID := range toDelete {
116 if groupHandle, have := agent.groupLoader.Lock(groupID); have {
Girish Gowdra4c4face2020-06-08 16:51:09 -0700117 affectedGroups[groupID] = groupHandle.GetReadOnly()
Kent Hagerman433a31a2020-05-20 19:04:48 -0400118 if err := groupHandle.Delete(ctx); err != nil {
119 return err
120 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400121 groupHandle.Unlock()
122
123 //TODO: this is another case where ordering guarantees are not being made,
124 // group deletion does not guarantee deletion of corresponding flows.
125 // an error while deleting flows can cause inconsistent state.
126 flows, err := agent.deleteFlowsHavingGroup(ctx, groupID)
127 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000128 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 -0400129 return err
130 }
131 for flowID, flow := range flows {
132 affectedFlows[flowID] = flow
133 }
134 }
135 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400136
Esin Karaman7eab1b92020-07-01 11:40:39 +0000137 if len(affectedGroups) == 0 {
138 logger.Debugw(ctx, "no-group-to-delete", log.Fields{"groupId": groupMod.GroupId})
139 return nil
140 }
141
142 var deviceRules *fu.DeviceRules
143 var err error
144
145 if len(affectedFlows) != 0 {
146 deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, affectedFlows, affectedGroups)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400147 if err != nil {
148 return err
149 }
Esin Karaman7eab1b92020-07-01 11:40:39 +0000150 } else {
151 //no flow is affected, just remove the groups
152 deviceRules = fu.NewDeviceRules()
153 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400154 }
Esin Karaman7eab1b92020-07-01 11:40:39 +0000155 //add groups to deviceRules
156 for _, groupEntry := range affectedGroups {
157 fg := fu.NewFlowsAndGroups()
158 fg.AddGroup(groupEntry)
159 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
160 }
161 logger.Debugw(ctx, "rules", log.Fields{"rules": deviceRules.String()})
162
163 // delete groups and related flows, if any
164 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &voltha.FlowMetadata{}, &ofp.OfpFlowMod{})
165
166 // Wait for completion
167 go func() {
168 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000169 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logical-device-id": agent.logicalDeviceID, "errors": res})
Esin Karaman7eab1b92020-07-01 11:40:39 +0000170 //TODO: Revert flow changes
171 }
172 }()
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400173 return nil
174}
175
176func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000177 logger.Debug(ctx, "groupModify")
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400178 if groupMod == nil {
179 return nil
180 }
181
182 groupID := groupMod.GroupId
Kent Hagerman433a31a2020-05-20 19:04:48 -0400183
184 groupHandle, have := agent.groupLoader.Lock(groupID)
185 if !have {
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400186 return fmt.Errorf("group-absent:%d", groupID)
187 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400188 defer groupHandle.Unlock()
189
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400190 //replace existing group entry with new group definition
191 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
192 deviceRules := fu.NewDeviceRules()
193 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
194 fg := fu.NewFlowsAndGroups()
195 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
196 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
197
Rohan Agrawal31f21802020-06-12 05:38:46 +0000198 logger.Debugw(ctx, "rules", log.Fields{"rules-for-group-modify": deviceRules.String()})
Kent Hagerman433a31a2020-05-20 19:04:48 -0400199
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400200 //update KV
Kent Hagerman433a31a2020-05-20 19:04:48 -0400201 if err := groupHandle.Update(ctx, groupEntry); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000202 logger.Errorw(ctx, "Cannot-update-logical-group", log.Fields{"logical-device-id": agent.logicalDeviceID})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400203 return err
204 }
205
206 // Update the devices
Rohan Agrawal31f21802020-06-12 05:38:46 +0000207 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400208
209 // Wait for completion
210 go func() {
211 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000212 logger.Warnw(ctx, "failure-updating-device-flows-groups", log.Fields{"logical-device-id": agent.logicalDeviceID, "errors": res})
Kent Hagerman3136fbd2020-05-14 10:30:45 -0400213 //TODO: Revert flow changes
214 }
215 }()
216 return nil
217}