e47a662599a1c8cf05f20874ab466c2689b5e078
[onosfw.git] /
1 /*
2  * Copyright 2015 Open Networking Laboratory
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 package org.onosproject.segmentrouting.grouphandler;
17
18 import static com.google.common.base.Preconditions.checkArgument;
19 import static org.slf4j.LoggerFactory.getLogger;
20
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.List;
26
27 import org.onlab.packet.MplsLabel;
28 import org.onosproject.core.ApplicationId;
29 import org.onosproject.segmentrouting.grouphandler.GroupBucketIdentifier.BucketOutputType;
30 import org.onosproject.store.service.EventuallyConsistentMap;
31 import org.onosproject.net.DeviceId;
32 import org.onosproject.net.PortNumber;
33 import org.onosproject.net.flow.DefaultTrafficTreatment;
34 import org.onosproject.net.flow.TrafficTreatment;
35 import org.onosproject.net.flowobjective.FlowObjectiveService;
36 import org.onosproject.net.group.GroupBucket;
37 import org.onosproject.net.link.LinkService;
38 import org.slf4j.Logger;
39
40 /**
41  * A module to create group chains based on the specified device
42  * ports and label stack to be applied on each port.
43  */
44 public class PolicyGroupHandler extends DefaultGroupHandler {
45
46     private final Logger log = getLogger(getClass());
47     private HashMap<PolicyGroupIdentifier, PolicyGroupIdentifier> dependentGroups = new HashMap<>();
48
49     /**
50      * Policy group handler constructor.
51      *
52      * @param deviceId device identifier
53      * @param appId application identifier
54      * @param config interface to retrieve the device properties
55      * @param linkService link service object
56      * @param flowObjService flow objective service object
57      * @param nsNextObjStore NeighborSet next objective store map
58      * @param subnetNextObjStore subnet next objective store map
59      */
60     public PolicyGroupHandler(DeviceId deviceId,
61                               ApplicationId appId,
62                               DeviceProperties config,
63                               LinkService linkService,
64                               FlowObjectiveService flowObjService,
65                               EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
66                                       Integer> nsNextObjStore,
67                               EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
68                                       Integer> subnetNextObjStore) {
69         super(deviceId, appId, config, linkService, flowObjService,
70               nsNextObjStore, subnetNextObjStore);
71     }
72
73     public PolicyGroupIdentifier createPolicyGroupChain(String id,
74                                                         List<PolicyGroupParams> params) {
75         List<GroupBucketIdentifier> bucketIds = new ArrayList<>();
76         for (PolicyGroupParams param: params) {
77             List<PortNumber> ports = param.getPorts();
78             if (ports == null) {
79                 log.warn("createPolicyGroupChain in sw {} with wrong "
80                         + "input parameters", deviceId);
81                 return null;
82             }
83
84             int labelStackSize = (param.getLabelStack() != null) ?
85                                       param.getLabelStack().size() : 0;
86
87             if (labelStackSize > 1) {
88                 for (PortNumber sp : ports) {
89                     PolicyGroupIdentifier previousGroupkey = null;
90                     DeviceId neighbor = portDeviceMap.get(sp);
91                     for (int idx = 0; idx < param.getLabelStack().size(); idx++) {
92                         int label = param.getLabelStack().get(idx);
93                         if (idx == (labelStackSize - 1)) {
94                             // Innermost Group
95                             GroupBucketIdentifier bucketId =
96                                     new GroupBucketIdentifier(label,
97                                                               previousGroupkey);
98                             bucketIds.add(bucketId);
99                         } else if (idx == 0) {
100                             // Outermost Group
101                             List<GroupBucket> outBuckets = new ArrayList<>();
102                             GroupBucketIdentifier bucketId =
103                                     new GroupBucketIdentifier(label, sp);
104                             PolicyGroupIdentifier key = new
105                                     PolicyGroupIdentifier(id,
106                                                           Collections.singletonList(param),
107                                                           Collections.singletonList(bucketId));
108                             TrafficTreatment.Builder tBuilder =
109                                     DefaultTrafficTreatment.builder();
110                             tBuilder.setOutput(sp)
111                                     .setEthDst(deviceConfig.
112                                                getDeviceMac(neighbor))
113                                     .setEthSrc(nodeMacAddr)
114                                     .pushMpls()
115                                     .setMpls(MplsLabel.mplsLabel(label));
116                             /*outBuckets.add(DefaultGroupBucket.
117                                            createSelectGroupBucket(tBuilder.build()));
118                             GroupDescription desc = new
119                                     DefaultGroupDescription(deviceId,
120                                                             GroupDescription.Type.INDIRECT,
121                                                             new GroupBuckets(outBuckets));
122                             //TODO: BoS*/
123                             previousGroupkey = key;
124                             //groupService.addGroup(desc);
125                             //TODO: Use nextObjective APIs here
126                         } else {
127                             // Intermediate Groups
128                             GroupBucketIdentifier bucketId =
129                                     new GroupBucketIdentifier(label,
130                                                               previousGroupkey);
131                             PolicyGroupIdentifier key = new
132                                     PolicyGroupIdentifier(id,
133                                                           Collections.singletonList(param),
134                                                           Collections.singletonList(bucketId));
135                             // Add to group dependency list
136                             dependentGroups.put(previousGroupkey, key);
137                             previousGroupkey = key;
138                         }
139                     }
140                 }
141             } else {
142                 int label = -1;
143                 if (labelStackSize == 1) {
144                     label = param.getLabelStack().get(0);
145                 }
146                 for (PortNumber sp : ports) {
147                     GroupBucketIdentifier bucketId =
148                             new GroupBucketIdentifier(label, sp);
149                     bucketIds.add(bucketId);
150                 }
151             }
152         }
153         PolicyGroupIdentifier innermostGroupkey = null;
154         if (!bucketIds.isEmpty()) {
155             innermostGroupkey = new
156                     PolicyGroupIdentifier(id,
157                                           params,
158                                           bucketIds);
159             // Add to group dependency list
160             boolean fullyResolved = true;
161             for (GroupBucketIdentifier bucketId:bucketIds) {
162                 if (bucketId.type() == BucketOutputType.GROUP) {
163                     dependentGroups.put(bucketId.outGroup(),
164                                         innermostGroupkey);
165                     fullyResolved = false;
166                 }
167             }
168
169             if (fullyResolved) {
170                 List<GroupBucket> outBuckets = new ArrayList<>();
171                 for (GroupBucketIdentifier bucketId:bucketIds) {
172                     DeviceId neighbor = portDeviceMap.
173                             get(bucketId.outPort());
174                     TrafficTreatment.Builder tBuilder =
175                             DefaultTrafficTreatment.builder();
176                     tBuilder.setOutput(bucketId.outPort())
177                             .setEthDst(deviceConfig.
178                                        getDeviceMac(neighbor))
179                             .setEthSrc(nodeMacAddr);
180                     if (bucketId.label() != NeighborSet.NO_EDGE_LABEL) {
181                         tBuilder.pushMpls()
182                             .setMpls(MplsLabel.mplsLabel(bucketId.label()));
183                     }
184                     //TODO: BoS
185                     /*outBuckets.add(DefaultGroupBucket.
186                                    createSelectGroupBucket(tBuilder.build()));*/
187                 }
188                 /*GroupDescription desc = new
189                         DefaultGroupDescription(deviceId,
190                                                 GroupDescription.Type.SELECT,
191                                                 new GroupBuckets(outBuckets));
192                 groupService.addGroup(desc);*/
193                 //TODO: Use nextObjective APIs here
194             }
195         }
196         return innermostGroupkey;
197     }
198
199     //TODO: Use nextObjective APIs to handle the group chains
200     /*@Override
201     protected void handleGroupEvent(GroupEvent event) {
202         if (event.type() == GroupEvent.Type.GROUP_ADDED) {
203             if (dependentGroups.get(event.subject().appCookie()) != null) {
204                 PolicyGroupIdentifier dependentGroupKey = dependentGroups.get(event.subject().appCookie());
205                 dependentGroups.remove(event.subject().appCookie());
206                 boolean fullyResolved = true;
207                 for (GroupBucketIdentifier bucketId:
208                             dependentGroupKey.bucketIds()) {
209                     if (bucketId.type() != BucketOutputType.GROUP) {
210                         continue;
211                     }
212                     if (dependentGroups.containsKey(bucketId.outGroup())) {
213                         fullyResolved = false;
214                         break;
215                     }
216                 }
217
218                 if (fullyResolved) {
219                     List<GroupBucket> outBuckets = new ArrayList<GroupBucket>();
220                     for (GroupBucketIdentifier bucketId:
221                                 dependentGroupKey.bucketIds()) {
222                         TrafficTreatment.Builder tBuilder =
223                                 DefaultTrafficTreatment.builder();
224                         if (bucketId.label() != NeighborSet.NO_EDGE_LABEL) {
225                             tBuilder.pushMpls()
226                                     .setMpls(MplsLabel.
227                                              mplsLabel(bucketId.label()));
228                         }
229                         //TODO: BoS
230                         if (bucketId.type() == BucketOutputType.PORT) {
231                             DeviceId neighbor = portDeviceMap.
232                                         get(bucketId.outPort());
233                             tBuilder.setOutput(bucketId.outPort())
234                                     .setEthDst(deviceConfig.
235                                                getDeviceMac(neighbor))
236                                      .setEthSrc(nodeMacAddr);
237                         } else {
238                             if (groupService.
239                                     getGroup(deviceId,
240                                              getGroupKey(bucketId.
241                                                        outGroup())) == null) {
242                                 throw new IllegalStateException();
243                             }
244                             GroupId indirectGroupId = groupService.
245                                     getGroup(deviceId,
246                                              getGroupKey(bucketId.
247                                                          outGroup())).id();
248                             tBuilder.group(indirectGroupId);
249                         }
250                         outBuckets.add(DefaultGroupBucket.
251                                        createSelectGroupBucket(tBuilder.build()));
252                     }
253                     GroupDescription desc = new
254                             DefaultGroupDescription(deviceId,
255                                                     GroupDescription.Type.SELECT,
256                                                     new GroupBuckets(outBuckets));
257                     groupService.addGroup(desc);
258                 }
259             }
260         }
261     }*/
262
263     public PolicyGroupIdentifier generatePolicyGroupKey(String id,
264                                    List<PolicyGroupParams> params) {
265         List<GroupBucketIdentifier> bucketIds = new ArrayList<>();
266         for (PolicyGroupParams param: params) {
267             List<PortNumber> ports = param.getPorts();
268             if (ports == null) {
269                 log.warn("generateGroupKey in sw {} with wrong "
270                         + "input parameters", deviceId);
271                 return null;
272             }
273
274             int labelStackSize = (param.getLabelStack() != null)
275                     ? param.getLabelStack().size() : 0;
276
277             if (labelStackSize > 1) {
278                 for (PortNumber sp : ports) {
279                     PolicyGroupIdentifier previousGroupkey = null;
280                     for (int idx = 0; idx < param.getLabelStack().size(); idx++) {
281                         int label = param.getLabelStack().get(idx);
282                         if (idx == (labelStackSize - 1)) {
283                             // Innermost Group
284                             GroupBucketIdentifier bucketId =
285                                     new GroupBucketIdentifier(label,
286                                                               previousGroupkey);
287                             bucketIds.add(bucketId);
288                         } else if (idx == 0) {
289                             // Outermost Group
290                             GroupBucketIdentifier bucketId =
291                                     new GroupBucketIdentifier(label, sp);
292                             PolicyGroupIdentifier key = new
293                                     PolicyGroupIdentifier(id,
294                                                           Collections.singletonList(param),
295                                                           Collections.singletonList(bucketId));
296                             previousGroupkey = key;
297                         } else {
298                             // Intermediate Groups
299                             GroupBucketIdentifier bucketId =
300                                     new GroupBucketIdentifier(label,
301                                                               previousGroupkey);
302                             PolicyGroupIdentifier key = new
303                                     PolicyGroupIdentifier(id,
304                                                           Collections.singletonList(param),
305                                                           Collections.singletonList(bucketId));
306                             previousGroupkey = key;
307                         }
308                     }
309                 }
310             } else {
311                 int label = -1;
312                 if (labelStackSize == 1) {
313                     label = param.getLabelStack().get(0);
314                 }
315                 for (PortNumber sp : ports) {
316                     GroupBucketIdentifier bucketId =
317                             new GroupBucketIdentifier(label, sp);
318                     bucketIds.add(bucketId);
319                 }
320             }
321         }
322         PolicyGroupIdentifier innermostGroupkey = null;
323         if (!bucketIds.isEmpty()) {
324             innermostGroupkey = new
325                     PolicyGroupIdentifier(id,
326                                           params,
327                                           bucketIds);
328         }
329         return innermostGroupkey;
330     }
331
332     public void removeGroupChain(PolicyGroupIdentifier key) {
333         checkArgument(key != null);
334         List<PolicyGroupIdentifier> groupsToBeDeleted = new ArrayList<>();
335         groupsToBeDeleted.add(key);
336
337         Iterator<PolicyGroupIdentifier> it =
338                 groupsToBeDeleted.iterator();
339
340         while (it.hasNext()) {
341             PolicyGroupIdentifier innerMostGroupKey = it.next();
342             for (GroupBucketIdentifier bucketId:
343                         innerMostGroupKey.bucketIds()) {
344                 if (bucketId.type() != BucketOutputType.GROUP) {
345                     groupsToBeDeleted.add(bucketId.outGroup());
346                 }
347             }
348             /*groupService.removeGroup(deviceId,
349                                      getGroupKey(innerMostGroupKey),
350                                      appId);*/
351             //TODO: Use nextObjective APIs here
352             it.remove();
353         }
354     }
355
356 }