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