blob: 6d28a11ee20dfdfb93efc62c342b5a2dbcb8cc43 [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;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070020import org.onlab.packet.MacAddress;
21import org.onlab.packet.VlanId;
Charles Chanf9e98652016-09-07 16:54:23 -070022import org.onosproject.core.ApplicationId;
Yi Tsengfa394de2017-02-01 11:26:40 -080023import org.onosproject.core.GroupId;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070024import org.onosproject.driver.extensions.Ofdpa3AllowVlanTranslationType;
Pier Ventre42287df2016-11-09 14:17:26 -080025import org.onosproject.driver.extensions.Ofdpa3PushCw;
26import org.onosproject.driver.extensions.Ofdpa3PushL2Header;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070027import org.onosproject.driver.extensions.OfdpaSetAllowVlanTranslation;
28import org.onosproject.driver.extensions.OfdpaSetVlanVid;
Pier Ventre42287df2016-11-09 14:17:26 -080029import org.onosproject.net.flow.DefaultTrafficTreatment;
Charles Chanf9e98652016-09-07 16:54:23 -070030import org.onosproject.net.flow.TrafficSelector;
31import org.onosproject.net.flow.TrafficTreatment;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070032import org.onosproject.net.flow.criteria.Criterion;
33import org.onosproject.net.flow.criteria.VlanIdCriterion;
Pier Ventre42287df2016-11-09 14:17:26 -080034import org.onosproject.net.flow.instructions.Instruction;
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070035import org.onosproject.net.flow.instructions.Instructions;
Pier Ventre42287df2016-11-09 14:17:26 -080036import org.onosproject.net.flow.instructions.L2ModificationInstruction;
37import org.onosproject.net.flow.instructions.L3ModificationInstruction;
38import org.onosproject.net.flowobjective.NextObjective;
39import org.onosproject.net.flowobjective.ObjectiveError;
40import org.onosproject.net.group.DefaultGroupBucket;
41import org.onosproject.net.group.DefaultGroupDescription;
42import org.onosproject.net.group.DefaultGroupKey;
43import org.onosproject.net.group.GroupBucket;
44import org.onosproject.net.group.GroupBuckets;
45import org.onosproject.net.group.GroupDescription;
46import org.onosproject.net.group.GroupKey;
47import org.slf4j.Logger;
48
49import java.util.ArrayDeque;
50import java.util.Collections;
51import java.util.Deque;
52import java.util.List;
53
Yi Tsengef19de12017-04-24 11:33:05 -070054import static org.onosproject.driver.pipeline.ofdpa.OfdpaGroupHandlerUtility.*;
Pier Ventre42287df2016-11-09 14:17:26 -080055import static org.onosproject.net.flow.instructions.L3ModificationInstruction.L3SubType.TTL_OUT;
56import static org.onosproject.net.group.GroupDescription.Type.INDIRECT;
57import static org.slf4j.LoggerFactory.getLogger;
Charles Chanf9e98652016-09-07 16:54:23 -070058
59/**
60 * Group handler for OFDPA2 pipeline.
61 */
62public class Ofdpa3GroupHandler extends Ofdpa2GroupHandler {
Pier Ventre42287df2016-11-09 14:17:26 -080063
64 private static final int PW_INTERNAL_VLAN = 4094;
65 private static final int MAX_DEPTH_UNPROTECTED_PW = 3;
66
67 private final Logger log = getLogger(getClass());
68
Charles Chanf9e98652016-09-07 16:54:23 -070069 @Override
70 protected GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId,
71 ApplicationId appId, boolean mpls,
72 TrafficSelector meta) {
Jonghwan Hyun800d9d02018-04-09 09:40:50 -070073 return isUnfiltered(treatment, meta) ?
74 createUnfilteredL2L3Chain(treatment, nextId, appId, false) :
75 createL2L3ChainInternal(treatment, nextId, appId, mpls, meta, false);
Charles Chanf9e98652016-09-07 16:54:23 -070076 }
Pier Ventre42287df2016-11-09 14:17:26 -080077
78 @Override
79 protected void processPwNextObjective(NextObjective nextObjective) {
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -080080
81 log.info("Started deploying nextObjective id={} for pseudowire", nextObjective.id());
82
Pier Ventre42287df2016-11-09 14:17:26 -080083 TrafficTreatment treatment = nextObjective.next().iterator().next();
84 Deque<GroupKey> gkeyChain = new ArrayDeque<>();
85 GroupChainElem groupChainElem;
86 GroupKey groupKey;
87 GroupDescription groupDescription;
88 // Now we separate the mpls actions from the l2/l3 actions
89 TrafficTreatment.Builder l2L3Treatment = DefaultTrafficTreatment.builder();
90 TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
91 createL2L3AndMplsTreatments(treatment, l2L3Treatment, mplsTreatment);
92 // We create the chain from mpls intf group to
93 // l2 intf group.
94 GroupInfo groupInfo = createL2L3ChainInternal(
95 l2L3Treatment.build(),
96 nextObjective.id(),
97 nextObjective.appId(),
98 true,
99 nextObjective.meta(),
100 false
101 );
102 if (groupInfo == null) {
103 log.error("Could not process nextObj={} in dev:{}", nextObjective.id(), deviceId);
104 Ofdpa2Pipeline.fail(nextObjective, ObjectiveError.GROUPINSTALLATIONFAILED);
105 return;
106 }
107 // We update the chain with the last two groups;
Yi Tsengef19de12017-04-24 11:33:05 -0700108 gkeyChain.addFirst(groupInfo.innerMostGroupDesc().appCookie());
109 gkeyChain.addFirst(groupInfo.nextGroupDesc().appCookie());
Pier Ventre42287df2016-11-09 14:17:26 -0800110 // We retrieve also all mpls instructions.
111 List<List<Instruction>> mplsInstructionSets = Lists.newArrayList();
112 List<Instruction> mplsInstructionSet = Lists.newArrayList();
113 L3ModificationInstruction l3Ins;
114 for (Instruction ins : treatment.allInstructions()) {
115 // Each mpls instruction set is delimited by a
116 // copy ttl outward action.
117 mplsInstructionSet.add(ins);
118 if (ins.type() == Instruction.Type.L3MODIFICATION) {
119 l3Ins = (L3ModificationInstruction) ins;
120 if (l3Ins.subtype() == TTL_OUT) {
121 mplsInstructionSets.add(mplsInstructionSet);
122 mplsInstructionSet = Lists.newArrayList();
123 }
Pier Ventre42287df2016-11-09 14:17:26 -0800124 }
125 }
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800126
Pier Ventre42287df2016-11-09 14:17:26 -0800127 if (mplsInstructionSets.size() > MAX_DEPTH_UNPROTECTED_PW) {
128 log.error("Next Objective for pseudo wire should have at "
129 + "most {} mpls instruction sets. Next Objective Id:{}",
130 MAX_DEPTH_UNPROTECTED_PW, nextObjective.id());
131 Ofdpa2Pipeline.fail(nextObjective, ObjectiveError.BADPARAMS);
132 return;
133 }
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800134
135 log.debug("Size of mpls instructions is {}.", mplsInstructionSets.size());
136 log.debug("mpls instructions sets are {}.", mplsInstructionSets);
137
Yi Tsengef19de12017-04-24 11:33:05 -0700138 int nextGid = groupInfo.nextGroupDesc().givenGroupId();
Pier Ventre42287df2016-11-09 14:17:26 -0800139 int index;
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800140
Pier Ventre42287df2016-11-09 14:17:26 -0800141 // We create the mpls tunnel label groups.
142 // In this case we need to use also the
143 // tunnel label group 2;
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800144 // this is for inter-co pws
Pier Ventre42287df2016-11-09 14:17:26 -0800145 if (mplsInstructionSets.size() == MAX_DEPTH_UNPROTECTED_PW) {
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800146
147 log.debug("Creating inter-co pw mpls chains with nextid {}", nextObjective.id());
148
Pier Ventre42287df2016-11-09 14:17:26 -0800149 // We deal with the label 2 group.
150 index = getNextAvailableIndex();
151 groupDescription = createMplsTunnelLabelGroup(
152 nextGid,
Yi Tsengef19de12017-04-24 11:33:05 -0700153 OfdpaMplsGroupSubType.MPLS_TUNNEL_LABEL_2,
Pier Ventre42287df2016-11-09 14:17:26 -0800154 index,
155 mplsInstructionSets.get(2),
156 nextObjective.appId()
157 );
158 groupKey = new DefaultGroupKey(
159 Ofdpa2Pipeline.appKryo.serialize(index)
160 );
161 // We update the chain.
Yi Tsengef19de12017-04-24 11:33:05 -0700162 groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
Pier Ventre42287df2016-11-09 14:17:26 -0800163 updatePendingGroups(
Yi Tsengef19de12017-04-24 11:33:05 -0700164 groupInfo.nextGroupDesc().appCookie(),
Pier Ventre42287df2016-11-09 14:17:26 -0800165 groupChainElem
166 );
167 gkeyChain.addFirst(groupKey);
168 // We have to create tunnel label group and
169 // l2 vpn group before to send the inner most
170 // group. We update the nextGid.
171 nextGid = groupDescription.givenGroupId();
Yi Tsengef19de12017-04-24 11:33:05 -0700172 groupInfo = new GroupInfo(groupInfo.innerMostGroupDesc(), groupDescription);
Pier Ventre42287df2016-11-09 14:17:26 -0800173
174 log.debug("Trying Label 2 Group: device:{} gid:{} gkey:{} nextId:{}",
175 deviceId, Integer.toHexString(nextGid),
176 groupKey, nextObjective.id());
177 }
Pier Ventre42287df2016-11-09 14:17:26 -0800178
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800179 // if treatment has 2 mpls labels, then this is a pseudowire from leaf to another leaf
180 // inside a single co
181 if (mplsInstructionSets.size() == 2) {
Pier Ventre42287df2016-11-09 14:17:26 -0800182
Andreas Pantelopoulos20474e02017-12-20 18:04:27 -0800183 log.debug("Creating leaf-leaf pw mpls chains with nextid {}", nextObjective.id());
184 // We deal with the label 1 group.
185 index = getNextAvailableIndex();
186 groupDescription = createMplsTunnelLabelGroup(nextGid,
187 OfdpaMplsGroupSubType.MPLS_TUNNEL_LABEL_1,
188 index,
189 mplsInstructionSets.get(1),
190 nextObjective.appId());
191 groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(index));
192 groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
193 updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), groupChainElem);
194 gkeyChain.addFirst(groupKey);
195 // We have to create the l2 vpn group before
196 // to send the inner most group.
197 nextGid = groupDescription.givenGroupId();
198 groupInfo = new GroupInfo(groupInfo.innerMostGroupDesc(), groupDescription);
199
200 log.debug("Trying Label 1 Group: device:{} gid:{} gkey:{} nextId:{}",
201 deviceId, Integer.toHexString(nextGid),
202 groupKey, nextObjective.id());
203 // Finally we create the l2 vpn group.
204 index = getNextAvailableIndex();
205 groupDescription = createMplsL2VpnGroup(nextGid, index,
206 mplsInstructionSets.get(0), nextObjective.appId());
207 groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(index));
208 groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
209 updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), groupChainElem);
210 gkeyChain.addFirst(groupKey);
211 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(Collections.singletonList(gkeyChain), nextObjective);
212 updatePendingNextObjective(groupKey, ofdpaGrp);
213
214 log.debug("Trying L2 Vpn Group: device:{} gid:{} gkey:{} nextId:{}", deviceId,
215 Integer.toHexString(nextGid), groupKey, nextObjective.id());
216 // Finally we send the innermost group.
217 log.debug("Sending innermost group {} in group chain on device {} ",
218 Integer.toHexString(groupInfo.innerMostGroupDesc().givenGroupId()), deviceId);
219 groupService.addGroup(groupInfo.innerMostGroupDesc());
220 }
221
222 // this is a pseudowire from leaf to spine,
223 // only one label is used
224 if (mplsInstructionSets.size() == 1) {
225
226 log.debug("Creating leaf-spine pw mpls chains with nextid {}", nextObjective.id());
227
228 // Finally we create the l2 vpn group.
229 index = getNextAvailableIndex();
230 groupDescription = createMplsL2VpnGroup(nextGid, index, mplsInstructionSets.get(0),
231 nextObjective.appId());
232 groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(index));
233 groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
234 updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), groupChainElem);
235 gkeyChain.addFirst(groupKey);
236 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(Collections.singletonList(gkeyChain), nextObjective);
237 updatePendingNextObjective(groupKey, ofdpaGrp);
238
239 log.debug("Trying L2 Vpn Group: device:{} gid:{} gkey:{} nextId:{}",
240 deviceId, Integer.toHexString(nextGid), groupKey, nextObjective.id());
241 // Finally we send the innermost group.
242 log.debug("Sending innermost group {} in group chain on device {} ",
243 Integer.toHexString(groupInfo.innerMostGroupDesc().givenGroupId()), deviceId);
244 groupService.addGroup(groupInfo.innerMostGroupDesc());
245 }
Pier Ventre42287df2016-11-09 14:17:26 -0800246 }
247
248 /**
249 * Helper method to create a mpls tunnel label group.
250 *
251 * @param nextGroupId the next group in the chain
252 * @param subtype the mpls tunnel label group subtype
253 * @param index the index of the group
254 * @param instructions the instructions to push
255 * @param applicationId the application id
256 * @return the group description
257 */
258 private GroupDescription createMplsTunnelLabelGroup(int nextGroupId,
Yi Tsengef19de12017-04-24 11:33:05 -0700259 OfdpaMplsGroupSubType subtype,
260 int index,
261 List<Instruction> instructions,
262 ApplicationId applicationId) {
Pier Ventre42287df2016-11-09 14:17:26 -0800263 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
264 // We add all the instructions.
265 instructions.forEach(treatment::add);
266 // We point the group to the next group.
Yi Tsengfa394de2017-02-01 11:26:40 -0800267 treatment.group(new GroupId(nextGroupId));
Pier Ventre42287df2016-11-09 14:17:26 -0800268 GroupBucket groupBucket = DefaultGroupBucket
269 .createIndirectGroupBucket(treatment.build());
270 // Finally we build the group description.
271 int groupId = makeMplsLabelGroupId(subtype, index);
272 GroupKey groupKey = new DefaultGroupKey(
273 Ofdpa2Pipeline.appKryo.serialize(index)
274 );
275 return new DefaultGroupDescription(
276 deviceId,
277 INDIRECT,
278 new GroupBuckets(Collections.singletonList(groupBucket)),
279 groupKey,
280 groupId,
281 applicationId
282 );
283 }
284
285 /**
286 * Helper method to create a mpls l2 vpn group.
287 *
288 * @param nextGroupId the next group in the chain
289 * @param index the index of the group
290 * @param instructions the instructions to push
291 * @param applicationId the application id
292 * @return the group description
293 */
294 private GroupDescription createMplsL2VpnGroup(int nextGroupId,
Yi Tsengef19de12017-04-24 11:33:05 -0700295 int index,
296 List<Instruction> instructions,
297 ApplicationId applicationId) {
Pier Ventre42287df2016-11-09 14:17:26 -0800298 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
299 // We add the extensions and the instructions.
300 treatment.extension(new Ofdpa3PushL2Header(), deviceId);
301 treatment.pushVlan();
302 instructions.forEach(treatment::add);
303 treatment.extension(new Ofdpa3PushCw(), deviceId);
304 // We point the group to the next group.
Yi Tsengfa394de2017-02-01 11:26:40 -0800305 treatment.group(new GroupId(nextGroupId));
Pier Ventre42287df2016-11-09 14:17:26 -0800306 GroupBucket groupBucket = DefaultGroupBucket
307 .createIndirectGroupBucket(treatment.build());
308 // Finally we build the group description.
Yi Tsengef19de12017-04-24 11:33:05 -0700309 int groupId = makeMplsLabelGroupId(OfdpaMplsGroupSubType.L2_VPN, index);
Pier Ventre42287df2016-11-09 14:17:26 -0800310 GroupKey groupKey = new DefaultGroupKey(
311 Ofdpa2Pipeline.appKryo.serialize(index)
312 );
313 return new DefaultGroupDescription(
314 deviceId,
315 INDIRECT,
316 new GroupBuckets(Collections.singletonList(groupBucket)),
317 groupKey,
318 groupId,
319 applicationId
320 );
321 }
322
323 /**
324 * Helper method for dividing the l2/l3 instructions from the mpls
325 * instructions.
326 *
327 * @param treatment the treatment to analyze
328 * @param l2L3Treatment the l2/l3 treatment builder
329 * @param mplsTreatment the mpls treatment builder
330 */
331 private void createL2L3AndMplsTreatments(TrafficTreatment treatment,
Yi Tsengef19de12017-04-24 11:33:05 -0700332 TrafficTreatment.Builder l2L3Treatment,
333 TrafficTreatment.Builder mplsTreatment) {
Pier Ventre42287df2016-11-09 14:17:26 -0800334
335 for (Instruction ins : treatment.allInstructions()) {
336
337 if (ins.type() == Instruction.Type.L2MODIFICATION) {
338 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
339 switch (l2ins.subtype()) {
340 // These instructions have to go in the l2/l3 treatment.
341 case ETH_DST:
342 case ETH_SRC:
343 case VLAN_ID:
344 case VLAN_POP:
345 l2L3Treatment.add(ins);
346 break;
347 // These instructions have to go in the mpls treatment.
348 case MPLS_BOS:
349 case DEC_MPLS_TTL:
350 case MPLS_LABEL:
351 case MPLS_PUSH:
352 mplsTreatment.add(ins);
353 break;
354 default:
Saurav Dasa4020382018-02-14 14:14:54 -0800355 log.warn("Driver does not handle TrafficTreatment"
356 + " L2Mod {} for pw next-obj", l2ins.subtype());
Pier Ventre42287df2016-11-09 14:17:26 -0800357 break;
358 }
359 } else if (ins.type() == Instruction.Type.OUTPUT) {
360 // The output goes in the l2/l3 treatment.
361 l2L3Treatment.add(ins);
362 } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
363 // We support partially the l3 instructions.
364 L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
365 switch (l3ins.subtype()) {
366 case TTL_OUT:
367 mplsTreatment.add(ins);
368 break;
369 default:
Saurav Dasa4020382018-02-14 14:14:54 -0800370 log.warn("Driver does not handle TrafficTreatment"
371 + " L3Mod for pw next-obj", l3ins.subtype());
Pier Ventre42287df2016-11-09 14:17:26 -0800372 }
373
374 } else {
375 log.warn("Driver does not handle this type of TrafficTreatment"
Saurav Dasa4020382018-02-14 14:14:54 -0800376 + " instruction for pw next-obj: {} - {}",
Pier Ventre42287df2016-11-09 14:17:26 -0800377 ins.type(), ins);
378 }
379 }
Pier Ventre42287df2016-11-09 14:17:26 -0800380 }
381 // TODO Introduce in the future an inner class to return two treatments
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700382
383 /**
384 * Internal implementation of createL2L3Chain for L2 unfiltered interface group.
385 *
386 * @param treatment that needs to be broken up to create the group chain
387 * @param nextId of the next objective that needs this group chain
388 * @param appId of the application that sent this next objective
389 * @param useSetVlanExtension use the setVlanVid extension that has is_present bit set to 0.
390 * @return GroupInfo containing the GroupDescription of the
391 * L2 Unfiltered Interface group(inner) and the GroupDescription of the (outer)
392 * L3Unicast group. May return null if there is an error in processing the chain.
393 */
394 private GroupInfo createUnfilteredL2L3Chain(TrafficTreatment treatment, int nextId,
395 ApplicationId appId, boolean useSetVlanExtension) {
396 // for the l2 unfiltered interface group, get port info
397 // for the l3 unicast group, get the src/dst mac, and vlan info
398 TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
399 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
400 VlanId vlanId;
401 long portNum = 0;
402 MacAddress srcMac;
403 MacAddress dstMac;
404 for (Instruction ins : treatment.allInstructions()) {
405 if (ins.type() == Instruction.Type.L2MODIFICATION) {
406 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
407 switch (l2ins.subtype()) {
408 case ETH_DST:
409 dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
410 outerTtb.setEthDst(dstMac);
411 break;
412 case ETH_SRC:
413 srcMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
414 outerTtb.setEthSrc(srcMac);
415 break;
416 case VLAN_ID:
417 vlanId = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId();
418 if (useSetVlanExtension) {
419 OfdpaSetVlanVid ofdpaSetVlanVid = new OfdpaSetVlanVid(vlanId);
420 outerTtb.extension(ofdpaSetVlanVid, deviceId);
421 } else {
422 outerTtb.setVlanId(vlanId);
423 }
424 break;
425 default:
426 break;
427 }
428 } else if (ins.type() == Instruction.Type.OUTPUT) {
429 portNum = ((Instructions.OutputInstruction) ins).port().toLong();
430 innerTtb.add(ins);
431 } else {
432 log.debug("Driver does not handle this type of TrafficTreatment"
433 + " instruction in l2l3chain: {} - {}", ins.type(),
434 ins);
435 }
436 }
437
438 innerTtb.extension(new OfdpaSetAllowVlanTranslation(
439 Ofdpa3AllowVlanTranslationType.ALLOW), deviceId);
440
441 // assemble information for ofdpa l2 unfiltered interface group
442 int l2groupId = l2UnfilteredGroupId(portNum);
443 // a globally unique groupkey that is different for ports in the same device,
444 // but different for the same portnumber on different devices. Also different
445 // for the various group-types created out of the same next objective.
446 int l2gk = l2UnfilteredGroupKey(deviceId, portNum);
447 final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa3Pipeline.appKryo.serialize(l2gk));
448
449 // assemble information for outer group (L3Unicast)
450 GroupDescription outerGrpDesc;
451 int l3unicastIndex = getNextAvailableIndex();
452 int l3groupId = L3_UNICAST_TYPE | (TYPE_MASK & l3unicastIndex);
453 final GroupKey l3groupkey = new DefaultGroupKey(
454 Ofdpa3Pipeline.appKryo.serialize(l3unicastIndex));
455 outerTtb.group(new GroupId(l2groupId));
456 // create the l3unicast group description to wait for the
457 // l2 unfiltered interface group to be processed
458 GroupBucket l3unicastGroupBucket =
459 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
460 outerGrpDesc = new DefaultGroupDescription(
461 deviceId,
462 GroupDescription.Type.INDIRECT,
463 new GroupBuckets(Collections.singletonList(l3unicastGroupBucket)),
464 l3groupkey,
465 l3groupId,
466 appId);
467 log.debug("Trying L3Unicast: device:{} gid:{} gkey:{} nextid:{}",
468 deviceId, Integer.toHexString(l3groupId),
469 l3groupkey, nextId);
470
471 // store l2groupkey with the groupChainElem for the outer-group that depends on it
472 GroupChainElem gce = new GroupChainElem(outerGrpDesc, 1, false, deviceId);
473 updatePendingGroups(l2groupkey, gce);
474
475 // create group description for the inner l2 unfiltered interface group
476 GroupBucket l2InterfaceGroupBucket =
477 DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build());
478 GroupDescription l2groupDescription =
479 new DefaultGroupDescription(deviceId,
480 GroupDescription.Type.INDIRECT,
481 new GroupBuckets(Collections.singletonList(l2InterfaceGroupBucket)),
482 l2groupkey,
483 l2groupId,
484 appId);
485 log.debug("Trying L2Unfiltered: device:{} gid:{} gkey:{} nextId:{}",
486 deviceId, Integer.toHexString(l2groupId), l2groupkey, nextId);
487 return new GroupInfo(l2groupDescription, outerGrpDesc);
488 }
489
490 /**
491 * Helper method to decide whether L2 Interface group or L2 Unfiltered group needs to be created.
492 * L2 Unfiltered group will be created if meta has VlanIdCriterion with VlanId.ANY, and
493 * treatment has set Vlan ID action.
494 *
495 * @param treatment treatment passed in by the application as part of the nextObjective
496 * @param meta metadata passed in by the application as part of the nextObjective
497 * @return true if L2 Unfiltered group needs to be created, false otherwise.
498 */
499 private boolean isUnfiltered(TrafficTreatment treatment, TrafficSelector meta) {
500 if (meta == null || treatment == null) {
501 return false;
502 }
503 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) meta.getCriterion(Criterion.Type.VLAN_VID);
504 if (vlanIdCriterion == null || !vlanIdCriterion.vlanId().equals(VlanId.ANY)) {
505 return false;
506 }
507
508 return treatment.allInstructions().stream()
509 .filter(i -> (i.type() == Instruction.Type.L2MODIFICATION
510 && ((L2ModificationInstruction) i).subtype() == L2ModificationInstruction.L2SubType.VLAN_ID))
511 .count() == 1;
512 }
513
Charles Chanf9e98652016-09-07 16:54:23 -0700514}