blob: 9b1d2830f3bd63c2095a37eb12aef042723d0a9f [file] [log] [blame]
Charles Chan425854b2016-04-11 15:32:12 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Charles Chan425854b2016-04-11 15:32:12 -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 Chan425854b2016-04-11 15:32:12 -070018
19import org.onlab.packet.MacAddress;
20import org.onlab.packet.VlanId;
21import org.onosproject.core.ApplicationId;
Yi Tsengfa394de2017-02-01 11:26:40 -080022import org.onosproject.core.GroupId;
Charles Chan425854b2016-04-11 15:32:12 -070023import org.onosproject.net.flow.DefaultTrafficTreatment;
24import org.onosproject.net.flow.TrafficSelector;
25import org.onosproject.net.flow.TrafficTreatment;
26import org.onosproject.net.flow.criteria.Criterion;
27import org.onosproject.net.flow.criteria.VlanIdCriterion;
28import org.onosproject.net.flow.instructions.Instruction;
29import org.onosproject.net.flow.instructions.Instructions;
30import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Pier Ventre140a8942016-11-02 07:26:38 -070031import org.onosproject.net.flowobjective.NextObjective;
Charles Chan425854b2016-04-11 15:32:12 -070032import org.onosproject.net.group.DefaultGroupBucket;
33import org.onosproject.net.group.DefaultGroupDescription;
34import org.onosproject.net.group.DefaultGroupKey;
35import org.onosproject.net.group.GroupBucket;
36import org.onosproject.net.group.GroupBuckets;
37import org.onosproject.net.group.GroupDescription;
38import org.onosproject.net.group.GroupKey;
39import org.slf4j.Logger;
40
Pier Ventre140a8942016-11-02 07:26:38 -070041import java.util.ArrayList;
Charles Chan425854b2016-04-11 15:32:12 -070042import java.util.Collections;
Pier Ventre140a8942016-11-02 07:26:38 -070043import java.util.Deque;
44import java.util.List;
Charles Chan425854b2016-04-11 15:32:12 -070045
Yi Tsengef19de12017-04-24 11:33:05 -070046import static org.onosproject.driver.pipeline.ofdpa.OfdpaGroupHandlerUtility.*;
Charles Chan425854b2016-04-11 15:32:12 -070047import static org.slf4j.LoggerFactory.getLogger;
48
49/**
50 * Group handler for CpqD OFDPA pipeline.
51 */
52public class CpqdOfdpa2GroupHandler extends Ofdpa2GroupHandler {
53 private final Logger log = getLogger(getClass());
54
55 @Override
56 protected GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId,
Yi Tsengef19de12017-04-24 11:33:05 -070057 ApplicationId appId, boolean mpls,
58 TrafficSelector meta) {
Andrea Campanella7c977b92018-05-30 21:39:45 -070059 if (createUnfiltered(treatment, meta)) {
60 return createUnfilteredL2L3Chain(treatment, nextId, appId);
61 }
Charles Chan425854b2016-04-11 15:32:12 -070062 // for the l2interface group, get vlan and port info
63 // for the outer group, get the src/dst mac, and vlan info
64 TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
65 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
66 VlanId vlanid = null;
67 long portNum = 0;
68 boolean setVlan = false, popVlan = false;
69 MacAddress srcMac = MacAddress.ZERO;
70 MacAddress dstMac = MacAddress.ZERO;
71 for (Instruction ins : treatment.allInstructions()) {
72 if (ins.type() == Instruction.Type.L2MODIFICATION) {
73 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
74 switch (l2ins.subtype()) {
75 case ETH_DST:
76 dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
77 outerTtb.setEthDst(dstMac);
78 break;
79 case ETH_SRC:
80 srcMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
81 outerTtb.setEthSrc(srcMac);
82 break;
83 case VLAN_ID:
84 vlanid = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId();
85 outerTtb.setVlanId(vlanid);
86 setVlan = true;
87 break;
88 case VLAN_POP:
89 innerTtb.popVlan();
90 popVlan = true;
91 break;
92 case DEC_MPLS_TTL:
93 case MPLS_LABEL:
94 case MPLS_POP:
95 case MPLS_PUSH:
96 case VLAN_PCP:
97 case VLAN_PUSH:
98 default:
99 break;
100 }
101 } else if (ins.type() == Instruction.Type.OUTPUT) {
102 portNum = ((Instructions.OutputInstruction) ins).port().toLong();
103 innerTtb.add(ins);
104 } else {
Saurav Dasa4020382018-02-14 14:14:54 -0800105 log.debug("Driver does not handle this type of TrafficTreatment"
106 + " instruction in l2l3chain: {} - {}", ins.type(),
107 ins);
Charles Chan425854b2016-04-11 15:32:12 -0700108 }
109 }
110
111 if (vlanid == null && meta != null) {
112 // use metadata if available
113 Criterion vidCriterion = meta.getCriterion(Criterion.Type.VLAN_VID);
114 if (vidCriterion != null) {
115 vlanid = ((VlanIdCriterion) vidCriterion).vlanId();
116 }
117 // if vlan is not set, use the vlan in metadata for outerTtb
118 if (vlanid != null && !setVlan) {
119 outerTtb.setVlanId(vlanid);
120 }
121 }
122
123 if (vlanid == null) {
124 log.error("Driver cannot process an L2/L3 group chain without "
Pier Ventre140a8942016-11-02 07:26:38 -0700125 + "egress vlan information for dev: {} port:{}",
126 deviceId, portNum);
Charles Chan425854b2016-04-11 15:32:12 -0700127 return null;
128 }
129
130 if (!setVlan && !popVlan) {
131 // untagged outgoing port
132 TrafficTreatment.Builder temp = DefaultTrafficTreatment.builder();
133 temp.popVlan();
134 innerTtb.build().allInstructions().forEach(i -> temp.add(i));
135 innerTtb = temp;
136 }
137
138 // assemble information for ofdpa l2interface group
139 int l2groupId = L2_INTERFACE_TYPE | (vlanid.toShort() << 16) | (int) portNum;
140 // a globally unique groupkey that is different for ports in the same device,
141 // but different for the same portnumber on different devices. Also different
142 // for the various group-types created out of the same next objective.
143 int l2gk = l2InterfaceGroupKey(deviceId, vlanid, portNum);
144 final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2gk));
145
146 // assemble information for outer group
147 GroupDescription outerGrpDesc = null;
148 if (mpls) {
149 // outer group is MPLSInteface
150 int mplsInterfaceIndex = getNextAvailableIndex();
151 int mplsgroupId = MPLS_INTERFACE_TYPE | (SUBTYPE_MASK & mplsInterfaceIndex);
152 final GroupKey mplsgroupkey = new DefaultGroupKey(
Pier Ventre140a8942016-11-02 07:26:38 -0700153 Ofdpa2Pipeline.appKryo.serialize(mplsInterfaceIndex));
Yi Tsengfa394de2017-02-01 11:26:40 -0800154 outerTtb.group(new GroupId(l2groupId));
Charles Chan425854b2016-04-11 15:32:12 -0700155 // create the mpls-interface group description to wait for the
156 // l2 interface group to be processed
157 GroupBucket mplsinterfaceGroupBucket =
158 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
159 outerGrpDesc = new DefaultGroupDescription(
160 deviceId,
161 GroupDescription.Type.INDIRECT,
162 new GroupBuckets(Collections.singletonList(
163 mplsinterfaceGroupBucket)),
164 mplsgroupkey,
165 mplsgroupId,
166 appId);
167 log.debug("Trying MPLS-Interface: device:{} gid:{} gkey:{} nextid:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700168 deviceId, Integer.toHexString(mplsgroupId),
169 mplsgroupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700170 } else {
171 // outer group is L3Unicast
172 int l3unicastIndex = getNextAvailableIndex();
173 int l3groupId = L3_UNICAST_TYPE | (TYPE_MASK & l3unicastIndex);
174 final GroupKey l3groupkey = new DefaultGroupKey(
Pier Ventre140a8942016-11-02 07:26:38 -0700175 Ofdpa2Pipeline.appKryo.serialize(l3unicastIndex));
Yi Tsengfa394de2017-02-01 11:26:40 -0800176 outerTtb.group(new GroupId(l2groupId));
Charles Chan425854b2016-04-11 15:32:12 -0700177 // create the l3unicast group description to wait for the
178 // l2 interface group to be processed
179 GroupBucket l3unicastGroupBucket =
180 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
181 outerGrpDesc = new DefaultGroupDescription(
182 deviceId,
183 GroupDescription.Type.INDIRECT,
184 new GroupBuckets(Collections.singletonList(
185 l3unicastGroupBucket)),
186 l3groupkey,
187 l3groupId,
188 appId);
189 log.debug("Trying L3Unicast: device:{} gid:{} gkey:{} nextid:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700190 deviceId, Integer.toHexString(l3groupId),
191 l3groupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700192 }
193
194 // store l2groupkey with the groupChainElem for the outer-group that depends on it
Yi Tsengef19de12017-04-24 11:33:05 -0700195 GroupChainElem gce = new GroupChainElem(outerGrpDesc,
196 1,
197 false,
198 deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700199 updatePendingGroups(l2groupkey, gce);
200
201 // create group description for the inner l2interfacegroup
202 GroupBucket l2InterfaceGroupBucket =
203 DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build());
204 GroupDescription l2groupDescription =
205 new DefaultGroupDescription(
206 deviceId,
207 GroupDescription.Type.INDIRECT,
208 new GroupBuckets(Collections.singletonList(
209 l2InterfaceGroupBucket)),
210 l2groupkey,
211 l2groupId,
212 appId);
213 log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700214 deviceId, Integer.toHexString(l2groupId),
215 l2groupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700216 return new GroupInfo(l2groupDescription, outerGrpDesc);
217 }
Pier Ventre140a8942016-11-02 07:26:38 -0700218
Pier Ventre140a8942016-11-02 07:26:38 -0700219 /**
220 * In OFDPA2 we do not support the MPLS-ECMP, while we do in
221 * CPQD implementation.
222 *
223 * @param nextObjective the hashed next objective to support.
224 */
225 @Override
226 protected void processHashedNextObjective(NextObjective nextObjective) {
227 // The case for MPLS-ECMP. For now, we try to create a MPLS-ECMP for
228 // the transport of a VPWS. The necessary info are contained in the
229 // meta selector. In particular we are looking for the case of BoS==False;
230 TrafficSelector metaSelector = nextObjective.meta();
Yi Tsengef19de12017-04-24 11:33:05 -0700231 if (metaSelector != null && Ofdpa2Pipeline.isNotMplsBos(metaSelector)) {
Pier Ventre140a8942016-11-02 07:26:38 -0700232 // storage for all group keys in the chain of groups created
233 List<Deque<GroupKey>> allGroupKeys = new ArrayList<>();
234 List<GroupInfo> unsentGroups = new ArrayList<>();
235 createHashBucketChains(nextObjective, allGroupKeys, unsentGroups);
236 // now we can create the outermost MPLS ECMP group
237 List<GroupBucket> mplsEcmpGroupBuckets = new ArrayList<>();
238 for (GroupInfo gi : unsentGroups) {
239 // create ECMP bucket to point to the outer group
240 TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder();
Yi Tsengef19de12017-04-24 11:33:05 -0700241 ttb.group(new GroupId(gi.nextGroupDesc().givenGroupId()));
Pier Ventre140a8942016-11-02 07:26:38 -0700242 GroupBucket sbucket = DefaultGroupBucket
243 .createSelectGroupBucket(ttb.build());
244 mplsEcmpGroupBuckets.add(sbucket);
245 }
246 int mplsEcmpIndex = getNextAvailableIndex();
Yi Tsengef19de12017-04-24 11:33:05 -0700247 int mplsEcmpGroupId = makeMplsForwardingGroupId(OfdpaMplsGroupSubType.MPLS_ECMP, mplsEcmpIndex);
Pier Ventre140a8942016-11-02 07:26:38 -0700248 GroupKey mplsEmpGroupKey = new DefaultGroupKey(
249 Ofdpa2Pipeline.appKryo.serialize(mplsEcmpIndex)
250 );
251 GroupDescription mplsEcmpGroupDesc = new DefaultGroupDescription(
252 deviceId,
253 GroupDescription.Type.SELECT,
254 new GroupBuckets(mplsEcmpGroupBuckets),
255 mplsEmpGroupKey,
256 mplsEcmpGroupId,
257 nextObjective.appId()
258 );
259 GroupChainElem mplsEcmpGce = new GroupChainElem(mplsEcmpGroupDesc,
260 mplsEcmpGroupBuckets.size(),
Yi Tsengef19de12017-04-24 11:33:05 -0700261 false,
262 deviceId);
Pier Ventre140a8942016-11-02 07:26:38 -0700263
264 // create objects for local and distributed storage
265 allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(mplsEmpGroupKey));
266 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObjective);
267
268 // store mplsEcmpGroupKey with the ofdpaGroupChain for the nextObjective
269 // that depends on it
270 updatePendingNextObjective(mplsEmpGroupKey, ofdpaGrp);
271
272 log.debug("Trying MPLS-ECMP: device:{} gid:{} gkey:{} nextId:{}",
273 deviceId, Integer.toHexString(mplsEcmpGroupId),
274 mplsEmpGroupKey, nextObjective.id());
275
276 // finally we are ready to send the innermost groups
277 for (GroupInfo gi : unsentGroups) {
278 log.debug("Sending innermost group {} in group chain on device {} ",
Yi Tsengef19de12017-04-24 11:33:05 -0700279 Integer.toHexString(gi.innerMostGroupDesc().givenGroupId()), deviceId);
280 updatePendingGroups(gi.nextGroupDesc().appCookie(), mplsEcmpGce);
281 groupService.addGroup(gi.innerMostGroupDesc());
Pier Ventre140a8942016-11-02 07:26:38 -0700282 }
283 return;
284 }
285 super.processHashedNextObjective(nextObjective);
286 }
Andrea Campanella7c977b92018-05-30 21:39:45 -0700287
288 /**
289 * Internal implementation of createL2L3Chain to handle double-tagged vlan.
290 * L3UG Group carries dummyVlanId and output port information in its groupId,
291 * and does not set vlan.
292 * L2UG Group only has OUTPUT instruction.
293 *
294 * @param treatment that needs to be broken up to create the group chain
295 * @param nextId of the next objective that needs this group chain
296 * @param appId of the application that sent this next objective
297 * @return GroupInfo containing the GroupDescription of the
298 * L2 Unfiltered Interface group(inner) and the GroupDescription of the (outer)
299 * L3Unicast group. May return null if there is an error in processing the chain.
300 */
301 private GroupInfo createUnfilteredL2L3Chain(TrafficTreatment treatment, int nextId,
302 ApplicationId appId) {
303 // for the l2 unfiltered interface group, get port info
304 // for the l3 unicast group, get the src/dst mac, and vlan info
305 TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
306 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
307 VlanId vlanId = VlanId.NONE;
308 long portNum = 0;
309 MacAddress srcMac;
310 MacAddress dstMac;
311 for (Instruction ins : treatment.allInstructions()) {
312 if (ins.type() == Instruction.Type.L2MODIFICATION) {
313 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
314 switch (l2ins.subtype()) {
315 case ETH_DST:
316 dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
317 outerTtb.setEthDst(dstMac);
318 break;
319 case ETH_SRC:
320 srcMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
321 outerTtb.setEthSrc(srcMac);
322 break;
323 case VLAN_ID:
324 vlanId = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId();
325 break;
326 default:
327 break;
328 }
329 } else if (ins.type() == Instruction.Type.OUTPUT) {
330 portNum = ((Instructions.OutputInstruction) ins).port().toLong();
331 innerTtb.add(ins);
332 } else {
333 log.debug("Driver does not handle this type of TrafficTreatment"
334 + " instruction in l2l3chain: {} - {}", ins.type(),
335 ins);
336 }
337 }
338
339 // assemble information for ofdpa l2 unfiltered interface group
340 int l2groupId = l2UnfilteredGroupId(portNum);
341 // a globally unique groupkey that is different for ports in the same device,
342 // but different for the same portnumber on different devices. Also different
343 // for the various group-types created out of the same next objective.
344 int l2gk = l2UnfilteredGroupKey(deviceId, portNum);
345 final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2gk));
346
347 // assemble information for outer group (L3Unicast)
348 GroupDescription outerGrpDesc;
349 int l3groupId = doubleVlanL3UnicastGroupId(vlanId, portNum);
350 final GroupKey l3groupkey = new DefaultGroupKey(
351 Ofdpa3Pipeline.appKryo.serialize(doubleVlanL3UnicastGroupKey(deviceId, vlanId, portNum)));
352 outerTtb.group(new GroupId(l2groupId));
353 // create the l3unicast group description to wait for the
354 // l2 unfiltered interface group to be processed
355 GroupBucket l3unicastGroupBucket =
356 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
357 outerGrpDesc = new DefaultGroupDescription(
358 deviceId,
359 GroupDescription.Type.INDIRECT,
360 new GroupBuckets(Collections.singletonList(l3unicastGroupBucket)),
361 l3groupkey,
362 l3groupId,
363 appId);
364 log.debug("Trying L3Unicast: device:{} gid:{} gkey:{} nextid:{}",
365 deviceId, Integer.toHexString(l3groupId),
366 l3groupkey, nextId);
367
368 // store l2groupkey with the groupChainElem for the outer-group that depends on it
369 OfdpaGroupHandlerUtility.GroupChainElem gce = new OfdpaGroupHandlerUtility.GroupChainElem(
370 outerGrpDesc, 1, false, deviceId);
371 updatePendingGroups(l2groupkey, gce);
372
373 // create group description for the inner l2 unfiltered interface group
374 GroupBucket l2InterfaceGroupBucket =
375 DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build());
376 GroupDescription l2groupDescription =
377 new DefaultGroupDescription(deviceId,
378 GroupDescription.Type.INDIRECT,
379 new GroupBuckets(Collections.singletonList(l2InterfaceGroupBucket)),
380 l2groupkey,
381 l2groupId,
382 appId);
383 log.debug("Trying L2Unfiltered: device:{} gid:{} gkey:{} nextId:{}",
384 deviceId, Integer.toHexString(l2groupId), l2groupkey, nextId);
385 return new OfdpaGroupHandlerUtility.GroupInfo(l2groupDescription, outerGrpDesc);
386 }
387
Charles Chan425854b2016-04-11 15:32:12 -0700388}