blob: 1c3033383a4ac2885d4139f629dba5ddd2af6a82 [file] [log] [blame]
Charles Chanf9e98652016-09-07 16:54:23 -07001/*
2 * Copyright 2016-present 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
17package org.onosproject.driver.pipeline;
18
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;
Pier Ventre42287df2016-11-09 14:17:26 -080022import org.onosproject.core.DefaultGroupId;
23import 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
47import static org.onosproject.driver.pipeline.Ofdpa2GroupHandler.OfdpaMplsGroupSubType.*;
48import 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) {
71 TrafficTreatment treatment = nextObjective.next().iterator().next();
72 Deque<GroupKey> gkeyChain = new ArrayDeque<>();
73 GroupChainElem groupChainElem;
74 GroupKey groupKey;
75 GroupDescription groupDescription;
76 // Now we separate the mpls actions from the l2/l3 actions
77 TrafficTreatment.Builder l2L3Treatment = DefaultTrafficTreatment.builder();
78 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
79 createL2L3AndMplsTreatments(treatment, l2L3Treatment, mplsTreatment);
80 // We create the chain from mpls intf group to
81 // l2 intf group.
82 GroupInfo groupInfo = createL2L3ChainInternal(
83 l2L3Treatment.build(),
84 nextObjective.id(),
85 nextObjective.appId(),
86 true,
87 nextObjective.meta(),
88 false
89 );
90 if (groupInfo == null) {
91 log.error("Could not process nextObj={} in dev:{}", nextObjective.id(), deviceId);
92 Ofdpa2Pipeline.fail(nextObjective, ObjectiveError.GROUPINSTALLATIONFAILED);
93 return;
94 }
95 // We update the chain with the last two groups;
96 gkeyChain.addFirst(groupInfo.getInnerMostGroupDesc().appCookie());
97 gkeyChain.addFirst(groupInfo.getNextGroupDesc().appCookie());
98 // We retrieve also all mpls instructions.
99 List<List<Instruction>> mplsInstructionSets = Lists.newArrayList();
100 List<Instruction> mplsInstructionSet = Lists.newArrayList();
101 L3ModificationInstruction l3Ins;
102 for (Instruction ins : treatment.allInstructions()) {
103 // Each mpls instruction set is delimited by a
104 // copy ttl outward action.
105 mplsInstructionSet.add(ins);
106 if (ins.type() == Instruction.Type.L3MODIFICATION) {
107 l3Ins = (L3ModificationInstruction) ins;
108 if (l3Ins.subtype() == TTL_OUT) {
109 mplsInstructionSets.add(mplsInstructionSet);
110 mplsInstructionSet = Lists.newArrayList();
111 }
112
113 }
114 }
115 if (mplsInstructionSets.size() > MAX_DEPTH_UNPROTECTED_PW) {
116 log.error("Next Objective for pseudo wire should have at "
117 + "most {} mpls instruction sets. Next Objective Id:{}",
118 MAX_DEPTH_UNPROTECTED_PW, nextObjective.id());
119 Ofdpa2Pipeline.fail(nextObjective, ObjectiveError.BADPARAMS);
120 return;
121 }
122 int nextGid = groupInfo.getNextGroupDesc().givenGroupId();
123 int index;
124 // We create the mpls tunnel label groups.
125 // In this case we need to use also the
126 // tunnel label group 2;
127 if (mplsInstructionSets.size() == MAX_DEPTH_UNPROTECTED_PW) {
128 // We deal with the label 2 group.
129 index = getNextAvailableIndex();
130 groupDescription = createMplsTunnelLabelGroup(
131 nextGid,
132 MPLS_TUNNEL_LABEL_2,
133 index,
134 mplsInstructionSets.get(2),
135 nextObjective.appId()
136 );
137 groupKey = new DefaultGroupKey(
138 Ofdpa2Pipeline.appKryo.serialize(index)
139 );
140 // We update the chain.
141 groupChainElem = new GroupChainElem(groupDescription, 1, false);
142 updatePendingGroups(
143 groupInfo.getNextGroupDesc().appCookie(),
144 groupChainElem
145 );
146 gkeyChain.addFirst(groupKey);
147 // We have to create tunnel label group and
148 // l2 vpn group before to send the inner most
149 // group. We update the nextGid.
150 nextGid = groupDescription.givenGroupId();
151 groupInfo = new GroupInfo(groupInfo.getInnerMostGroupDesc(), groupDescription);
152
153 log.debug("Trying Label 2 Group: device:{} gid:{} gkey:{} nextId:{}",
154 deviceId, Integer.toHexString(nextGid),
155 groupKey, nextObjective.id());
156 }
157 // We deal with the label 1 group.
158 index = getNextAvailableIndex();
159 groupDescription = createMplsTunnelLabelGroup(
160 nextGid,
161 MPLS_TUNNEL_LABEL_1,
162 index,
163 mplsInstructionSets.get(1),
164 nextObjective.appId()
165 );
166 groupKey = new DefaultGroupKey(
167 Ofdpa2Pipeline.appKryo.serialize(index)
168 );
169 groupChainElem = new GroupChainElem(groupDescription, 1, false);
170 updatePendingGroups(
171 groupInfo.getNextGroupDesc().appCookie(),
172 groupChainElem
173 );
174 gkeyChain.addFirst(groupKey);
175 // We have to create the l2 vpn group before
176 // to send the inner most group.
177 nextGid = groupDescription.givenGroupId();
178 groupInfo = new GroupInfo(groupInfo.getInnerMostGroupDesc(), groupDescription);
179
180 log.debug("Trying Label 1 Group: device:{} gid:{} gkey:{} nextId:{}",
181 deviceId, Integer.toHexString(nextGid),
182 groupKey, nextObjective.id());
183 // Finally we create the l2 vpn group.
184 index = getNextAvailableIndex();
185 groupDescription = createMplsL2VpnGroup(
186 nextGid,
187 index,
188 mplsInstructionSets.get(0),
189 nextObjective.appId()
190 );
191 groupKey = new DefaultGroupKey(
192 Ofdpa2Pipeline.appKryo.serialize(index)
193 );
194 groupChainElem = new GroupChainElem(groupDescription, 1, false);
195 updatePendingGroups(
196 groupInfo.getNextGroupDesc().appCookie(),
197 groupChainElem
198 );
199 gkeyChain.addFirst(groupKey);
200 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(
201 Collections.singletonList(gkeyChain),
202 nextObjective
203 );
204 updatePendingNextObjective(groupKey, ofdpaGrp);
205
206 log.debug("Trying L2 Vpn Group: device:{} gid:{} gkey:{} nextId:{}",
207 deviceId, Integer.toHexString(nextGid),
208 groupKey, nextObjective.id());
209 // Finally we send the innermost group.
210 log.debug("Sending innermost group {} in group chain on device {} ",
211 Integer.toHexString(groupInfo.getInnerMostGroupDesc().givenGroupId()), deviceId);
212 groupService.addGroup(groupInfo.getInnerMostGroupDesc());
213 }
214
215 /**
216 * Helper method to create a mpls tunnel label group.
217 *
218 * @param nextGroupId the next group in the chain
219 * @param subtype the mpls tunnel label group subtype
220 * @param index the index of the group
221 * @param instructions the instructions to push
222 * @param applicationId the application id
223 * @return the group description
224 */
225 private GroupDescription createMplsTunnelLabelGroup(int nextGroupId,
226 OfdpaMplsGroupSubType subtype,
227 int index,
228 List<Instruction> instructions,
229 ApplicationId applicationId) {
230 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
231 // We add all the instructions.
232 instructions.forEach(treatment::add);
233 // We point the group to the next group.
234 treatment.group(new DefaultGroupId(nextGroupId));
235 GroupBucket groupBucket = DefaultGroupBucket
236 .createIndirectGroupBucket(treatment.build());
237 // Finally we build the group description.
238 int groupId = makeMplsLabelGroupId(subtype, index);
239 GroupKey groupKey = new DefaultGroupKey(
240 Ofdpa2Pipeline.appKryo.serialize(index)
241 );
242 return new DefaultGroupDescription(
243 deviceId,
244 INDIRECT,
245 new GroupBuckets(Collections.singletonList(groupBucket)),
246 groupKey,
247 groupId,
248 applicationId
249 );
250 }
251
252 /**
253 * Helper method to create a mpls l2 vpn group.
254 *
255 * @param nextGroupId the next group in the chain
256 * @param index the index of the group
257 * @param instructions the instructions to push
258 * @param applicationId the application id
259 * @return the group description
260 */
261 private GroupDescription createMplsL2VpnGroup(int nextGroupId,
262 int index,
263 List<Instruction> instructions,
264 ApplicationId applicationId) {
265 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
266 // We add the extensions and the instructions.
267 treatment.extension(new Ofdpa3PushL2Header(), deviceId);
268 treatment.pushVlan();
269 instructions.forEach(treatment::add);
270 treatment.extension(new Ofdpa3PushCw(), deviceId);
271 // We point the group to the next group.
272 treatment.group(new DefaultGroupId(nextGroupId));
273 GroupBucket groupBucket = DefaultGroupBucket
274 .createIndirectGroupBucket(treatment.build());
275 // Finally we build the group description.
276 int groupId = makeMplsLabelGroupId(L2_VPN, index);
277 GroupKey groupKey = new DefaultGroupKey(
278 Ofdpa2Pipeline.appKryo.serialize(index)
279 );
280 return new DefaultGroupDescription(
281 deviceId,
282 INDIRECT,
283 new GroupBuckets(Collections.singletonList(groupBucket)),
284 groupKey,
285 groupId,
286 applicationId
287 );
288 }
289
290 /**
291 * Helper method for dividing the l2/l3 instructions from the mpls
292 * instructions.
293 *
294 * @param treatment the treatment to analyze
295 * @param l2L3Treatment the l2/l3 treatment builder
296 * @param mplsTreatment the mpls treatment builder
297 */
298 private void createL2L3AndMplsTreatments(TrafficTreatment treatment,
299 TrafficTreatment.Builder l2L3Treatment,
300 TrafficTreatment.Builder mplsTreatment) {
301
302 for (Instruction ins : treatment.allInstructions()) {
303
304 if (ins.type() == Instruction.Type.L2MODIFICATION) {
305 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
306 switch (l2ins.subtype()) {
307 // These instructions have to go in the l2/l3 treatment.
308 case ETH_DST:
309 case ETH_SRC:
310 case VLAN_ID:
311 case VLAN_POP:
312 l2L3Treatment.add(ins);
313 break;
314 // These instructions have to go in the mpls treatment.
315 case MPLS_BOS:
316 case DEC_MPLS_TTL:
317 case MPLS_LABEL:
318 case MPLS_PUSH:
319 mplsTreatment.add(ins);
320 break;
321 default:
322 log.warn("Driver does not handle this type of TrafficTreatment"
323 + " instruction in nextObjectives: {} - {}",
324 ins.type(), ins);
325 break;
326 }
327 } else if (ins.type() == Instruction.Type.OUTPUT) {
328 // The output goes in the l2/l3 treatment.
329 l2L3Treatment.add(ins);
330 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
331 // We support partially the l3 instructions.
332 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
333 switch (l3ins.subtype()) {
334 case TTL_OUT:
335 mplsTreatment.add(ins);
336 break;
337 default:
338 log.warn("Driver does not handle this type of TrafficTreatment"
339 + " instruction in nextObjectives: {} - {}",
340 ins.type(), ins);
341 }
342
343 } else {
344 log.warn("Driver does not handle this type of TrafficTreatment"
345 + " instruction in nextObjectives: {} - {}",
346 ins.type(), ins);
347 }
348 }
349 // We add in a transparent way the set vlan to 4094.
350 l2L3Treatment.setVlanId(VlanId.vlanId((short) PW_INTERNAL_VLAN));
351 }
352 // TODO Introduce in the future an inner class to return two treatments
Charles Chanf9e98652016-09-07 16:54:23 -0700353}