blob: a261d43fc936907cdc2afd545c54536a6954f6d1 [file] [log] [blame]
Charles Chanf9e98652016-09-07 16:54:23 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Charles Chanf9e98652016-09-07 16:54:23 -07003 *
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
Yi Tsengef19de12017-04-24 11:33:05 -070017package org.onosproject.driver.pipeline.ofdpa;
Charles Chanf9e98652016-09-07 16:54:23 -070018
Pier Ventre42287df2016-11-09 14:17:26 -080019import com.google.common.collect.Lists;
20import org.onlab.packet.VlanId;
Charles Chanf9e98652016-09-07 16:54:23 -070021import org.onosproject.core.ApplicationId;
Yi Tsengfa394de2017-02-01 11:26:40 -080022import org.onosproject.core.GroupId;
Pier Ventre42287df2016-11-09 14:17:26 -080023import org.onosproject.driver.extensions.Ofdpa3PushCw;
24import org.onosproject.driver.extensions.Ofdpa3PushL2Header;
25import org.onosproject.net.flow.DefaultTrafficTreatment;
Charles Chanf9e98652016-09-07 16:54:23 -070026import org.onosproject.net.flow.TrafficSelector;
27import org.onosproject.net.flow.TrafficTreatment;
Pier Ventre42287df2016-11-09 14:17:26 -080028import org.onosproject.net.flow.instructions.Instruction;
29import org.onosproject.net.flow.instructions.L2ModificationInstruction;
30import org.onosproject.net.flow.instructions.L3ModificationInstruction;
31import org.onosproject.net.flowobjective.NextObjective;
32import org.onosproject.net.flowobjective.ObjectiveError;
33import org.onosproject.net.group.DefaultGroupBucket;
34import org.onosproject.net.group.DefaultGroupDescription;
35import org.onosproject.net.group.DefaultGroupKey;
36import org.onosproject.net.group.GroupBucket;
37import org.onosproject.net.group.GroupBuckets;
38import org.onosproject.net.group.GroupDescription;
39import org.onosproject.net.group.GroupKey;
40import org.slf4j.Logger;
41
42import java.util.ArrayDeque;
43import java.util.Collections;
44import java.util.Deque;
45import java.util.List;
46
Yi Tsengef19de12017-04-24 11:33:05 -070047import static org.onosproject.driver.pipeline.ofdpa.OfdpaGroupHandlerUtility.*;
Pier Ventre42287df2016-11-09 14:17:26 -080048import static org.onosproject.net.flow.instructions.L3ModificationInstruction.L3SubType.TTL_OUT;
49import static org.onosproject.net.group.GroupDescription.Type.INDIRECT;
50import static org.slf4j.LoggerFactory.getLogger;
Charles Chanf9e98652016-09-07 16:54:23 -070051
52/**
53 * Group handler for OFDPA2 pipeline.
54 */
55public class Ofdpa3GroupHandler extends Ofdpa2GroupHandler {
Pier Ventre42287df2016-11-09 14:17:26 -080056
57 private static final int PW_INTERNAL_VLAN = 4094;
58 private static final int MAX_DEPTH_UNPROTECTED_PW = 3;
59
60 private final Logger log = getLogger(getClass());
61
Charles Chanf9e98652016-09-07 16:54:23 -070062 @Override
63 protected GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId,
64 ApplicationId appId, boolean mpls,
65 TrafficSelector meta) {
66 return createL2L3ChainInternal(treatment, nextId, appId, mpls, meta, false);
67 }
Pier Ventre42287df2016-11-09 14:17:26 -080068
69 @Override
70 protected void processPwNextObjective(NextObjective nextObjective) {
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -080071
72 log.info("Started deploying nextObjective id={} for pseudowire", nextObjective.id());
73
Pier Ventre42287df2016-11-09 14:17:26 -080074 TrafficTreatment treatment = nextObjective.next().iterator().next();
75 Deque<GroupKey> gkeyChain = new ArrayDeque<>();
76 GroupChainElem groupChainElem;
77 GroupKey groupKey;
78 GroupDescription groupDescription;
79 // Now we separate the mpls actions from the l2/l3 actions
80 TrafficTreatment.Builder l2L3Treatment = DefaultTrafficTreatment.builder();
81 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
82 createL2L3AndMplsTreatments(treatment, l2L3Treatment, mplsTreatment);
83 // We create the chain from mpls intf group to
84 // l2 intf group.
85 GroupInfo groupInfo = createL2L3ChainInternal(
86 l2L3Treatment.build(),
87 nextObjective.id(),
88 nextObjective.appId(),
89 true,
90 nextObjective.meta(),
91 false
92 );
93 if (groupInfo == null) {
94 log.error("Could not process nextObj={} in dev:{}", nextObjective.id(), deviceId);
95 Ofdpa2Pipeline.fail(nextObjective, ObjectiveError.GROUPINSTALLATIONFAILED);
96 return;
97 }
98 // We update the chain with the last two groups;
Yi Tsengef19de12017-04-24 11:33:05 -070099 gkeyChain.addFirst(groupInfo.innerMostGroupDesc().appCookie());
100 gkeyChain.addFirst(groupInfo.nextGroupDesc().appCookie());
Pier Ventre42287df2016-11-09 14:17:26 -0800101 // We retrieve also all mpls instructions.
102 List<List<Instruction>> mplsInstructionSets = Lists.newArrayList();
103 List<Instruction> mplsInstructionSet = Lists.newArrayList();
104 L3ModificationInstruction l3Ins;
105 for (Instruction ins : treatment.allInstructions()) {
106 // Each mpls instruction set is delimited by a
107 // copy ttl outward action.
108 mplsInstructionSet.add(ins);
109 if (ins.type() == Instruction.Type.L3MODIFICATION) {
110 l3Ins = (L3ModificationInstruction) ins;
111 if (l3Ins.subtype() == TTL_OUT) {
112 mplsInstructionSets.add(mplsInstructionSet);
113 mplsInstructionSet = Lists.newArrayList();
114 }
Pier Ventre42287df2016-11-09 14:17:26 -0800115 }
116 }
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800117
Pier Ventre42287df2016-11-09 14:17:26 -0800118 if (mplsInstructionSets.size() > MAX_DEPTH_UNPROTECTED_PW) {
119 log.error("Next Objective for pseudo wire should have at "
120 + "most {} mpls instruction sets. Next Objective Id:{}",
121 MAX_DEPTH_UNPROTECTED_PW, nextObjective.id());
122 Ofdpa2Pipeline.fail(nextObjective, ObjectiveError.BADPARAMS);
123 return;
124 }
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800125
126 log.debug("Size of mpls instructions is {}.", mplsInstructionSets.size());
127 log.debug("mpls instructions sets are {}.", mplsInstructionSets);
128
Yi Tsengef19de12017-04-24 11:33:05 -0700129 int nextGid = groupInfo.nextGroupDesc().givenGroupId();
Pier Ventre42287df2016-11-09 14:17:26 -0800130 int index;
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800131
Pier Ventre42287df2016-11-09 14:17:26 -0800132 // We create the mpls tunnel label groups.
133 // In this case we need to use also the
134 // tunnel label group 2;
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800135 // this is for inter-co pws
Pier Ventre42287df2016-11-09 14:17:26 -0800136 if (mplsInstructionSets.size() == MAX_DEPTH_UNPROTECTED_PW) {
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800137
138 log.debug("Creating inter-co pw mpls chains with nextid {}", nextObjective.id());
139
Pier Ventre42287df2016-11-09 14:17:26 -0800140 // We deal with the label 2 group.
141 index = getNextAvailableIndex();
142 groupDescription = createMplsTunnelLabelGroup(
143 nextGid,
Yi Tsengef19de12017-04-24 11:33:05 -0700144 OfdpaMplsGroupSubType.MPLS_TUNNEL_LABEL_2,
Pier Ventre42287df2016-11-09 14:17:26 -0800145 index,
146 mplsInstructionSets.get(2),
147 nextObjective.appId()
148 );
149 groupKey = new DefaultGroupKey(
150 Ofdpa2Pipeline.appKryo.serialize(index)
151 );
152 // We update the chain.
Yi Tsengef19de12017-04-24 11:33:05 -0700153 groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
Pier Ventre42287df2016-11-09 14:17:26 -0800154 updatePendingGroups(
Yi Tsengef19de12017-04-24 11:33:05 -0700155 groupInfo.nextGroupDesc().appCookie(),
Pier Ventre42287df2016-11-09 14:17:26 -0800156 groupChainElem
157 );
158 gkeyChain.addFirst(groupKey);
159 // We have to create tunnel label group and
160 // l2 vpn group before to send the inner most
161 // group. We update the nextGid.
162 nextGid = groupDescription.givenGroupId();
Yi Tsengef19de12017-04-24 11:33:05 -0700163 groupInfo = new GroupInfo(groupInfo.innerMostGroupDesc(), groupDescription);
Pier Ventre42287df2016-11-09 14:17:26 -0800164
165 log.debug("Trying Label 2 Group: device:{} gid:{} gkey:{} nextId:{}",
166 deviceId, Integer.toHexString(nextGid),
167 groupKey, nextObjective.id());
168 }
Pier Ventre42287df2016-11-09 14:17:26 -0800169
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800170 // if treatment has 2 mpls labels, then this is a pseudowire from leaf to another leaf
171 // inside a single co
172 if (mplsInstructionSets.size() == 2) {
Pier Ventre42287df2016-11-09 14:17:26 -0800173
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800174 log.debug("Creating leaf-leaf pw mpls chains with nextid {}", nextObjective.id());
175 // We deal with the label 1 group.
176 index = getNextAvailableIndex();
177 groupDescription = createMplsTunnelLabelGroup(nextGid,
178 OfdpaMplsGroupSubType.MPLS_TUNNEL_LABEL_1,
179 index,
180 mplsInstructionSets.get(1),
181 nextObjective.appId());
182 groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(index));
183 groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
184 updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), groupChainElem);
185 gkeyChain.addFirst(groupKey);
186 // We have to create the l2 vpn group before
187 // to send the inner most group.
188 nextGid = groupDescription.givenGroupId();
189 groupInfo = new GroupInfo(groupInfo.innerMostGroupDesc(), groupDescription);
190
191 log.debug("Trying Label 1 Group: device:{} gid:{} gkey:{} nextId:{}",
192 deviceId, Integer.toHexString(nextGid),
193 groupKey, nextObjective.id());
194 // Finally we create the l2 vpn group.
195 index = getNextAvailableIndex();
196 groupDescription = createMplsL2VpnGroup(nextGid, index,
197 mplsInstructionSets.get(0), nextObjective.appId());
198 groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(index));
199 groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
200 updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), groupChainElem);
201 gkeyChain.addFirst(groupKey);
202 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(Collections.singletonList(gkeyChain), nextObjective);
203 updatePendingNextObjective(groupKey, ofdpaGrp);
204
205 log.debug("Trying L2 Vpn Group: device:{} gid:{} gkey:{} nextId:{}", deviceId,
206 Integer.toHexString(nextGid), groupKey, nextObjective.id());
207 // Finally we send the innermost group.
208 log.debug("Sending innermost group {} in group chain on device {} ",
209 Integer.toHexString(groupInfo.innerMostGroupDesc().givenGroupId()), deviceId);
210 groupService.addGroup(groupInfo.innerMostGroupDesc());
211 }
212
213 // this is a pseudowire from leaf to spine,
214 // only one label is used
215 if (mplsInstructionSets.size() == 1) {
216
217 log.debug("Creating leaf-spine pw mpls chains with nextid {}", nextObjective.id());
218
219 // Finally we create the l2 vpn group.
220 index = getNextAvailableIndex();
221 groupDescription = createMplsL2VpnGroup(nextGid, index, mplsInstructionSets.get(0),
222 nextObjective.appId());
223 groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(index));
224 groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
225 updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), groupChainElem);
226 gkeyChain.addFirst(groupKey);
227 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(Collections.singletonList(gkeyChain), nextObjective);
228 updatePendingNextObjective(groupKey, ofdpaGrp);
229
230 log.debug("Trying L2 Vpn Group: device:{} gid:{} gkey:{} nextId:{}",
231 deviceId, Integer.toHexString(nextGid), groupKey, nextObjective.id());
232 // Finally we send the innermost group.
233 log.debug("Sending innermost group {} in group chain on device {} ",
234 Integer.toHexString(groupInfo.innerMostGroupDesc().givenGroupId()), deviceId);
235 groupService.addGroup(groupInfo.innerMostGroupDesc());
236 }
Pier Ventre42287df2016-11-09 14:17:26 -0800237 }
238
239 /**
240 * Helper method to create a mpls tunnel label group.
241 *
242 * @param nextGroupId the next group in the chain
243 * @param subtype the mpls tunnel label group subtype
244 * @param index the index of the group
245 * @param instructions the instructions to push
246 * @param applicationId the application id
247 * @return the group description
248 */
249 private GroupDescription createMplsTunnelLabelGroup(int nextGroupId,
Yi Tsengef19de12017-04-24 11:33:05 -0700250 OfdpaMplsGroupSubType subtype,
251 int index,
252 List<Instruction> instructions,
253 ApplicationId applicationId) {
Pier Ventre42287df2016-11-09 14:17:26 -0800254 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
255 // We add all the instructions.
256 instructions.forEach(treatment::add);
257 // We point the group to the next group.
Yi Tsengfa394de2017-02-01 11:26:40 -0800258 treatment.group(new GroupId(nextGroupId));
Pier Ventre42287df2016-11-09 14:17:26 -0800259 GroupBucket groupBucket = DefaultGroupBucket
260 .createIndirectGroupBucket(treatment.build());
261 // Finally we build the group description.
262 int groupId = makeMplsLabelGroupId(subtype, index);
263 GroupKey groupKey = new DefaultGroupKey(
264 Ofdpa2Pipeline.appKryo.serialize(index)
265 );
266 return new DefaultGroupDescription(
267 deviceId,
268 INDIRECT,
269 new GroupBuckets(Collections.singletonList(groupBucket)),
270 groupKey,
271 groupId,
272 applicationId
273 );
274 }
275
276 /**
277 * Helper method to create a mpls l2 vpn group.
278 *
279 * @param nextGroupId the next group in the chain
280 * @param index the index of the group
281 * @param instructions the instructions to push
282 * @param applicationId the application id
283 * @return the group description
284 */
285 private GroupDescription createMplsL2VpnGroup(int nextGroupId,
Yi Tsengef19de12017-04-24 11:33:05 -0700286 int index,
287 List<Instruction> instructions,
288 ApplicationId applicationId) {
Pier Ventre42287df2016-11-09 14:17:26 -0800289 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
290 // We add the extensions and the instructions.
291 treatment.extension(new Ofdpa3PushL2Header(), deviceId);
292 treatment.pushVlan();
293 instructions.forEach(treatment::add);
294 treatment.extension(new Ofdpa3PushCw(), deviceId);
295 // We point the group to the next group.
Yi Tsengfa394de2017-02-01 11:26:40 -0800296 treatment.group(new GroupId(nextGroupId));
Pier Ventre42287df2016-11-09 14:17:26 -0800297 GroupBucket groupBucket = DefaultGroupBucket
298 .createIndirectGroupBucket(treatment.build());
299 // Finally we build the group description.
Yi Tsengef19de12017-04-24 11:33:05 -0700300 int groupId = makeMplsLabelGroupId(OfdpaMplsGroupSubType.L2_VPN, index);
Pier Ventre42287df2016-11-09 14:17:26 -0800301 GroupKey groupKey = new DefaultGroupKey(
302 Ofdpa2Pipeline.appKryo.serialize(index)
303 );
304 return new DefaultGroupDescription(
305 deviceId,
306 INDIRECT,
307 new GroupBuckets(Collections.singletonList(groupBucket)),
308 groupKey,
309 groupId,
310 applicationId
311 );
312 }
313
314 /**
315 * Helper method for dividing the l2/l3 instructions from the mpls
316 * instructions.
317 *
318 * @param treatment the treatment to analyze
319 * @param l2L3Treatment the l2/l3 treatment builder
320 * @param mplsTreatment the mpls treatment builder
321 */
322 private void createL2L3AndMplsTreatments(TrafficTreatment treatment,
Yi Tsengef19de12017-04-24 11:33:05 -0700323 TrafficTreatment.Builder l2L3Treatment,
324 TrafficTreatment.Builder mplsTreatment) {
Pier Ventre42287df2016-11-09 14:17:26 -0800325
326 for (Instruction ins : treatment.allInstructions()) {
327
328 if (ins.type() == Instruction.Type.L2MODIFICATION) {
329 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
330 switch (l2ins.subtype()) {
331 // These instructions have to go in the l2/l3 treatment.
332 case ETH_DST:
333 case ETH_SRC:
334 case VLAN_ID:
335 case VLAN_POP:
336 l2L3Treatment.add(ins);
337 break;
338 // These instructions have to go in the mpls treatment.
339 case MPLS_BOS:
340 case DEC_MPLS_TTL:
341 case MPLS_LABEL:
342 case MPLS_PUSH:
343 mplsTreatment.add(ins);
344 break;
345 default:
346 log.warn("Driver does not handle this type of TrafficTreatment"
347 + " instruction in nextObjectives: {} - {}",
348 ins.type(), ins);
349 break;
350 }
351 } else if (ins.type() == Instruction.Type.OUTPUT) {
352 // The output goes in the l2/l3 treatment.
353 l2L3Treatment.add(ins);
354 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
355 // We support partially the l3 instructions.
356 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
357 switch (l3ins.subtype()) {
358 case TTL_OUT:
359 mplsTreatment.add(ins);
360 break;
361 default:
362 log.warn("Driver does not handle this type of TrafficTreatment"
363 + " instruction in nextObjectives: {} - {}",
364 ins.type(), ins);
365 }
366
367 } else {
368 log.warn("Driver does not handle this type of TrafficTreatment"
369 + " instruction in nextObjectives: {} - {}",
370 ins.type(), ins);
371 }
372 }
373 // We add in a transparent way the set vlan to 4094.
374 l2L3Treatment.setVlanId(VlanId.vlanId((short) PW_INTERNAL_VLAN));
375 }
376 // TODO Introduce in the future an inner class to return two treatments
Charles Chanf9e98652016-09-07 16:54:23 -0700377}