blob: 711ba3aa8882f5d991599b5e85eb4faf2c128af7 [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/**
Charles Chanab591602019-01-22 17:25:04 -080050 * Group handler for Open vSwitch OFDPA pipeline.
Charles Chan425854b2016-04-11 15:32:12 -070051 */
Charles Chanab591602019-01-22 17:25:04 -080052public class OvsOfdpaGroupHandler extends Ofdpa2GroupHandler {
Charles Chan425854b2016-04-11 15:32:12 -070053 private final Logger log = getLogger(getClass());
54
55 @Override
Charles Chanab591602019-01-22 17:25:04 -080056 protected boolean supportCopyTtl() {
57 return false;
58 }
59
60 @Override
61 protected boolean supportSetMplsBos() {
62 return false;
63 }
64
65 @Override
66 protected boolean requireVlanPopBeforeMplsPush() {
67 return true;
68 }
69
70 @Override
Charles Chan425854b2016-04-11 15:32:12 -070071 protected GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId,
Yi Tsengef19de12017-04-24 11:33:05 -070072 ApplicationId appId, boolean mpls,
73 TrafficSelector meta) {
Andrea Campanella7c977b92018-05-30 21:39:45 -070074 if (createUnfiltered(treatment, meta)) {
75 return createUnfilteredL2L3Chain(treatment, nextId, appId);
76 }
Charles Chan425854b2016-04-11 15:32:12 -070077 // for the l2interface group, get vlan and port info
78 // for the outer group, get the src/dst mac, and vlan info
79 TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
80 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
81 VlanId vlanid = null;
82 long portNum = 0;
83 boolean setVlan = false, popVlan = false;
84 MacAddress srcMac = MacAddress.ZERO;
85 MacAddress dstMac = MacAddress.ZERO;
86 for (Instruction ins : treatment.allInstructions()) {
87 if (ins.type() == Instruction.Type.L2MODIFICATION) {
88 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
89 switch (l2ins.subtype()) {
90 case ETH_DST:
91 dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
92 outerTtb.setEthDst(dstMac);
93 break;
94 case ETH_SRC:
95 srcMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
96 outerTtb.setEthSrc(srcMac);
97 break;
98 case VLAN_ID:
99 vlanid = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId();
100 outerTtb.setVlanId(vlanid);
101 setVlan = true;
102 break;
103 case VLAN_POP:
104 innerTtb.popVlan();
105 popVlan = true;
106 break;
107 case DEC_MPLS_TTL:
108 case MPLS_LABEL:
109 case MPLS_POP:
110 case MPLS_PUSH:
111 case VLAN_PCP:
112 case VLAN_PUSH:
113 default:
114 break;
115 }
116 } else if (ins.type() == Instruction.Type.OUTPUT) {
117 portNum = ((Instructions.OutputInstruction) ins).port().toLong();
118 innerTtb.add(ins);
119 } else {
Saurav Dasa4020382018-02-14 14:14:54 -0800120 log.debug("Driver does not handle this type of TrafficTreatment"
121 + " instruction in l2l3chain: {} - {}", ins.type(),
122 ins);
Charles Chan425854b2016-04-11 15:32:12 -0700123 }
124 }
125
126 if (vlanid == null && meta != null) {
127 // use metadata if available
128 Criterion vidCriterion = meta.getCriterion(Criterion.Type.VLAN_VID);
129 if (vidCriterion != null) {
130 vlanid = ((VlanIdCriterion) vidCriterion).vlanId();
131 }
132 // if vlan is not set, use the vlan in metadata for outerTtb
133 if (vlanid != null && !setVlan) {
134 outerTtb.setVlanId(vlanid);
135 }
136 }
137
138 if (vlanid == null) {
139 log.error("Driver cannot process an L2/L3 group chain without "
Pier Ventre140a8942016-11-02 07:26:38 -0700140 + "egress vlan information for dev: {} port:{}",
141 deviceId, portNum);
Charles Chan425854b2016-04-11 15:32:12 -0700142 return null;
143 }
144
145 if (!setVlan && !popVlan) {
146 // untagged outgoing port
147 TrafficTreatment.Builder temp = DefaultTrafficTreatment.builder();
148 temp.popVlan();
149 innerTtb.build().allInstructions().forEach(i -> temp.add(i));
150 innerTtb = temp;
151 }
152
153 // assemble information for ofdpa l2interface group
154 int l2groupId = L2_INTERFACE_TYPE | (vlanid.toShort() << 16) | (int) portNum;
155 // a globally unique groupkey that is different for ports in the same device,
156 // but different for the same portnumber on different devices. Also different
157 // for the various group-types created out of the same next objective.
158 int l2gk = l2InterfaceGroupKey(deviceId, vlanid, portNum);
159 final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2gk));
160
161 // assemble information for outer group
162 GroupDescription outerGrpDesc = null;
163 if (mpls) {
164 // outer group is MPLSInteface
165 int mplsInterfaceIndex = getNextAvailableIndex();
166 int mplsgroupId = MPLS_INTERFACE_TYPE | (SUBTYPE_MASK & mplsInterfaceIndex);
167 final GroupKey mplsgroupkey = new DefaultGroupKey(
Pier Ventre140a8942016-11-02 07:26:38 -0700168 Ofdpa2Pipeline.appKryo.serialize(mplsInterfaceIndex));
Yi Tsengfa394de2017-02-01 11:26:40 -0800169 outerTtb.group(new GroupId(l2groupId));
Charles Chan425854b2016-04-11 15:32:12 -0700170 // create the mpls-interface group description to wait for the
171 // l2 interface group to be processed
172 GroupBucket mplsinterfaceGroupBucket =
173 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
174 outerGrpDesc = new DefaultGroupDescription(
175 deviceId,
176 GroupDescription.Type.INDIRECT,
177 new GroupBuckets(Collections.singletonList(
178 mplsinterfaceGroupBucket)),
179 mplsgroupkey,
180 mplsgroupId,
181 appId);
182 log.debug("Trying MPLS-Interface: device:{} gid:{} gkey:{} nextid:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700183 deviceId, Integer.toHexString(mplsgroupId),
184 mplsgroupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700185 } else {
186 // outer group is L3Unicast
187 int l3unicastIndex = getNextAvailableIndex();
188 int l3groupId = L3_UNICAST_TYPE | (TYPE_MASK & l3unicastIndex);
189 final GroupKey l3groupkey = new DefaultGroupKey(
Pier Ventre140a8942016-11-02 07:26:38 -0700190 Ofdpa2Pipeline.appKryo.serialize(l3unicastIndex));
Yi Tsengfa394de2017-02-01 11:26:40 -0800191 outerTtb.group(new GroupId(l2groupId));
Charles Chan425854b2016-04-11 15:32:12 -0700192 // create the l3unicast group description to wait for the
193 // l2 interface group to be processed
194 GroupBucket l3unicastGroupBucket =
195 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
196 outerGrpDesc = new DefaultGroupDescription(
197 deviceId,
198 GroupDescription.Type.INDIRECT,
199 new GroupBuckets(Collections.singletonList(
200 l3unicastGroupBucket)),
201 l3groupkey,
202 l3groupId,
203 appId);
204 log.debug("Trying L3Unicast: device:{} gid:{} gkey:{} nextid:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700205 deviceId, Integer.toHexString(l3groupId),
206 l3groupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700207 }
208
209 // store l2groupkey with the groupChainElem for the outer-group that depends on it
Yi Tsengef19de12017-04-24 11:33:05 -0700210 GroupChainElem gce = new GroupChainElem(outerGrpDesc,
211 1,
212 false,
213 deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700214 updatePendingGroups(l2groupkey, gce);
215
216 // create group description for the inner l2interfacegroup
217 GroupBucket l2InterfaceGroupBucket =
218 DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build());
219 GroupDescription l2groupDescription =
220 new DefaultGroupDescription(
221 deviceId,
222 GroupDescription.Type.INDIRECT,
223 new GroupBuckets(Collections.singletonList(
224 l2InterfaceGroupBucket)),
225 l2groupkey,
226 l2groupId,
227 appId);
228 log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700229 deviceId, Integer.toHexString(l2groupId),
230 l2groupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700231 return new GroupInfo(l2groupDescription, outerGrpDesc);
232 }
Pier Ventre140a8942016-11-02 07:26:38 -0700233
Pier Ventre140a8942016-11-02 07:26:38 -0700234 /**
235 * In OFDPA2 we do not support the MPLS-ECMP, while we do in
Charles Chanab591602019-01-22 17:25:04 -0800236 * Open vSwitch implementation.
Pier Ventre140a8942016-11-02 07:26:38 -0700237 *
238 * @param nextObjective the hashed next objective to support.
239 */
240 @Override
241 protected void processHashedNextObjective(NextObjective nextObjective) {
242 // The case for MPLS-ECMP. For now, we try to create a MPLS-ECMP for
243 // the transport of a VPWS. The necessary info are contained in the
244 // meta selector. In particular we are looking for the case of BoS==False;
245 TrafficSelector metaSelector = nextObjective.meta();
Yi Tsengef19de12017-04-24 11:33:05 -0700246 if (metaSelector != null && Ofdpa2Pipeline.isNotMplsBos(metaSelector)) {
Pier Ventre140a8942016-11-02 07:26:38 -0700247 // storage for all group keys in the chain of groups created
248 List<Deque<GroupKey>> allGroupKeys = new ArrayList<>();
249 List<GroupInfo> unsentGroups = new ArrayList<>();
250 createHashBucketChains(nextObjective, allGroupKeys, unsentGroups);
251 // now we can create the outermost MPLS ECMP group
252 List<GroupBucket> mplsEcmpGroupBuckets = new ArrayList<>();
253 for (GroupInfo gi : unsentGroups) {
254 // create ECMP bucket to point to the outer group
255 TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder();
Yi Tsengef19de12017-04-24 11:33:05 -0700256 ttb.group(new GroupId(gi.nextGroupDesc().givenGroupId()));
Pier Ventre140a8942016-11-02 07:26:38 -0700257 GroupBucket sbucket = DefaultGroupBucket
258 .createSelectGroupBucket(ttb.build());
259 mplsEcmpGroupBuckets.add(sbucket);
260 }
261 int mplsEcmpIndex = getNextAvailableIndex();
Yi Tsengef19de12017-04-24 11:33:05 -0700262 int mplsEcmpGroupId = makeMplsForwardingGroupId(OfdpaMplsGroupSubType.MPLS_ECMP, mplsEcmpIndex);
Pier Ventre140a8942016-11-02 07:26:38 -0700263 GroupKey mplsEmpGroupKey = new DefaultGroupKey(
264 Ofdpa2Pipeline.appKryo.serialize(mplsEcmpIndex)
265 );
266 GroupDescription mplsEcmpGroupDesc = new DefaultGroupDescription(
267 deviceId,
268 GroupDescription.Type.SELECT,
269 new GroupBuckets(mplsEcmpGroupBuckets),
270 mplsEmpGroupKey,
271 mplsEcmpGroupId,
272 nextObjective.appId()
273 );
274 GroupChainElem mplsEcmpGce = new GroupChainElem(mplsEcmpGroupDesc,
275 mplsEcmpGroupBuckets.size(),
Yi Tsengef19de12017-04-24 11:33:05 -0700276 false,
277 deviceId);
Pier Ventre140a8942016-11-02 07:26:38 -0700278
279 // create objects for local and distributed storage
280 allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(mplsEmpGroupKey));
281 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObjective);
282
283 // store mplsEcmpGroupKey with the ofdpaGroupChain for the nextObjective
284 // that depends on it
285 updatePendingNextObjective(mplsEmpGroupKey, ofdpaGrp);
286
287 log.debug("Trying MPLS-ECMP: device:{} gid:{} gkey:{} nextId:{}",
288 deviceId, Integer.toHexString(mplsEcmpGroupId),
289 mplsEmpGroupKey, nextObjective.id());
290
291 // finally we are ready to send the innermost groups
292 for (GroupInfo gi : unsentGroups) {
293 log.debug("Sending innermost group {} in group chain on device {} ",
Yi Tsengef19de12017-04-24 11:33:05 -0700294 Integer.toHexString(gi.innerMostGroupDesc().givenGroupId()), deviceId);
295 updatePendingGroups(gi.nextGroupDesc().appCookie(), mplsEcmpGce);
296 groupService.addGroup(gi.innerMostGroupDesc());
Pier Ventre140a8942016-11-02 07:26:38 -0700297 }
298 return;
299 }
300 super.processHashedNextObjective(nextObjective);
301 }
Andrea Campanella7c977b92018-05-30 21:39:45 -0700302
303 /**
304 * Internal implementation of createL2L3Chain to handle double-tagged vlan.
305 * L3UG Group carries dummyVlanId and output port information in its groupId,
306 * and does not set vlan.
307 * L2UG Group only has OUTPUT instruction.
308 *
309 * @param treatment that needs to be broken up to create the group chain
310 * @param nextId of the next objective that needs this group chain
311 * @param appId of the application that sent this next objective
312 * @return GroupInfo containing the GroupDescription of the
313 * L2 Unfiltered Interface group(inner) and the GroupDescription of the (outer)
314 * L3Unicast group. May return null if there is an error in processing the chain.
315 */
316 private GroupInfo createUnfilteredL2L3Chain(TrafficTreatment treatment, int nextId,
317 ApplicationId appId) {
318 // for the l2 unfiltered interface group, get port info
319 // for the l3 unicast group, get the src/dst mac, and vlan info
320 TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
321 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
322 VlanId vlanId = VlanId.NONE;
323 long portNum = 0;
324 MacAddress srcMac;
325 MacAddress dstMac;
326 for (Instruction ins : treatment.allInstructions()) {
327 if (ins.type() == Instruction.Type.L2MODIFICATION) {
328 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
329 switch (l2ins.subtype()) {
330 case ETH_DST:
331 dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
332 outerTtb.setEthDst(dstMac);
333 break;
334 case ETH_SRC:
335 srcMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
336 outerTtb.setEthSrc(srcMac);
337 break;
338 case VLAN_ID:
339 vlanId = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId();
340 break;
341 default:
342 break;
343 }
344 } else if (ins.type() == Instruction.Type.OUTPUT) {
345 portNum = ((Instructions.OutputInstruction) ins).port().toLong();
346 innerTtb.add(ins);
347 } else {
348 log.debug("Driver does not handle this type of TrafficTreatment"
349 + " instruction in l2l3chain: {} - {}", ins.type(),
350 ins);
351 }
352 }
353
354 // assemble information for ofdpa l2 unfiltered interface group
355 int l2groupId = l2UnfilteredGroupId(portNum);
356 // a globally unique groupkey that is different for ports in the same device,
357 // but different for the same portnumber on different devices. Also different
358 // for the various group-types created out of the same next objective.
359 int l2gk = l2UnfilteredGroupKey(deviceId, portNum);
360 final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2gk));
361
362 // assemble information for outer group (L3Unicast)
363 GroupDescription outerGrpDesc;
364 int l3groupId = doubleVlanL3UnicastGroupId(vlanId, portNum);
365 final GroupKey l3groupkey = new DefaultGroupKey(
366 Ofdpa3Pipeline.appKryo.serialize(doubleVlanL3UnicastGroupKey(deviceId, vlanId, portNum)));
367 outerTtb.group(new GroupId(l2groupId));
368 // create the l3unicast group description to wait for the
369 // l2 unfiltered interface group to be processed
370 GroupBucket l3unicastGroupBucket =
371 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
372 outerGrpDesc = new DefaultGroupDescription(
373 deviceId,
374 GroupDescription.Type.INDIRECT,
375 new GroupBuckets(Collections.singletonList(l3unicastGroupBucket)),
376 l3groupkey,
377 l3groupId,
378 appId);
379 log.debug("Trying L3Unicast: device:{} gid:{} gkey:{} nextid:{}",
380 deviceId, Integer.toHexString(l3groupId),
381 l3groupkey, nextId);
382
383 // store l2groupkey with the groupChainElem for the outer-group that depends on it
384 OfdpaGroupHandlerUtility.GroupChainElem gce = new OfdpaGroupHandlerUtility.GroupChainElem(
385 outerGrpDesc, 1, false, deviceId);
386 updatePendingGroups(l2groupkey, gce);
387
388 // create group description for the inner l2 unfiltered interface group
389 GroupBucket l2InterfaceGroupBucket =
390 DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build());
391 GroupDescription l2groupDescription =
392 new DefaultGroupDescription(deviceId,
393 GroupDescription.Type.INDIRECT,
394 new GroupBuckets(Collections.singletonList(l2InterfaceGroupBucket)),
395 l2groupkey,
396 l2groupId,
397 appId);
398 log.debug("Trying L2Unfiltered: device:{} gid:{} gkey:{} nextId:{}",
399 deviceId, Integer.toHexString(l2groupId), l2groupkey, nextId);
400 return new OfdpaGroupHandlerUtility.GroupInfo(l2groupDescription, outerGrpDesc);
401 }
402
Charles Chan425854b2016-04-11 15:32:12 -0700403}