blob: 401e924cf2a1311a5ced0e8a84edf81c50139420 [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) {
Charles Chan425854b2016-04-11 15:32:12 -070059 // for the l2interface group, get vlan and port info
60 // for the outer group, get the src/dst mac, and vlan info
61 TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
62 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
63 VlanId vlanid = null;
64 long portNum = 0;
65 boolean setVlan = false, popVlan = false;
66 MacAddress srcMac = MacAddress.ZERO;
67 MacAddress dstMac = MacAddress.ZERO;
68 for (Instruction ins : treatment.allInstructions()) {
69 if (ins.type() == Instruction.Type.L2MODIFICATION) {
70 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
71 switch (l2ins.subtype()) {
72 case ETH_DST:
73 dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
74 outerTtb.setEthDst(dstMac);
75 break;
76 case ETH_SRC:
77 srcMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
78 outerTtb.setEthSrc(srcMac);
79 break;
80 case VLAN_ID:
81 vlanid = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId();
82 outerTtb.setVlanId(vlanid);
83 setVlan = true;
84 break;
85 case VLAN_POP:
86 innerTtb.popVlan();
87 popVlan = true;
88 break;
89 case DEC_MPLS_TTL:
90 case MPLS_LABEL:
91 case MPLS_POP:
92 case MPLS_PUSH:
93 case VLAN_PCP:
94 case VLAN_PUSH:
95 default:
96 break;
97 }
98 } else if (ins.type() == Instruction.Type.OUTPUT) {
99 portNum = ((Instructions.OutputInstruction) ins).port().toLong();
100 innerTtb.add(ins);
101 } else {
102 log.warn("Driver does not handle this type of TrafficTreatment"
Pier Ventre140a8942016-11-02 07:26:38 -0700103 + " instruction in nextObjectives: {}", ins.type());
Charles Chan425854b2016-04-11 15:32:12 -0700104 }
105 }
106
107 if (vlanid == null && meta != null) {
108 // use metadata if available
109 Criterion vidCriterion = meta.getCriterion(Criterion.Type.VLAN_VID);
110 if (vidCriterion != null) {
111 vlanid = ((VlanIdCriterion) vidCriterion).vlanId();
112 }
113 // if vlan is not set, use the vlan in metadata for outerTtb
114 if (vlanid != null && !setVlan) {
115 outerTtb.setVlanId(vlanid);
116 }
117 }
118
119 if (vlanid == null) {
120 log.error("Driver cannot process an L2/L3 group chain without "
Pier Ventre140a8942016-11-02 07:26:38 -0700121 + "egress vlan information for dev: {} port:{}",
122 deviceId, portNum);
Charles Chan425854b2016-04-11 15:32:12 -0700123 return null;
124 }
125
126 if (!setVlan && !popVlan) {
127 // untagged outgoing port
128 TrafficTreatment.Builder temp = DefaultTrafficTreatment.builder();
129 temp.popVlan();
130 innerTtb.build().allInstructions().forEach(i -> temp.add(i));
131 innerTtb = temp;
132 }
133
134 // assemble information for ofdpa l2interface group
135 int l2groupId = L2_INTERFACE_TYPE | (vlanid.toShort() << 16) | (int) portNum;
136 // a globally unique groupkey that is different for ports in the same device,
137 // but different for the same portnumber on different devices. Also different
138 // for the various group-types created out of the same next objective.
139 int l2gk = l2InterfaceGroupKey(deviceId, vlanid, portNum);
140 final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2gk));
141
142 // assemble information for outer group
143 GroupDescription outerGrpDesc = null;
144 if (mpls) {
145 // outer group is MPLSInteface
146 int mplsInterfaceIndex = getNextAvailableIndex();
147 int mplsgroupId = MPLS_INTERFACE_TYPE | (SUBTYPE_MASK & mplsInterfaceIndex);
148 final GroupKey mplsgroupkey = new DefaultGroupKey(
Pier Ventre140a8942016-11-02 07:26:38 -0700149 Ofdpa2Pipeline.appKryo.serialize(mplsInterfaceIndex));
Yi Tsengfa394de2017-02-01 11:26:40 -0800150 outerTtb.group(new GroupId(l2groupId));
Charles Chan425854b2016-04-11 15:32:12 -0700151 // create the mpls-interface group description to wait for the
152 // l2 interface group to be processed
153 GroupBucket mplsinterfaceGroupBucket =
154 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
155 outerGrpDesc = new DefaultGroupDescription(
156 deviceId,
157 GroupDescription.Type.INDIRECT,
158 new GroupBuckets(Collections.singletonList(
159 mplsinterfaceGroupBucket)),
160 mplsgroupkey,
161 mplsgroupId,
162 appId);
163 log.debug("Trying MPLS-Interface: device:{} gid:{} gkey:{} nextid:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700164 deviceId, Integer.toHexString(mplsgroupId),
165 mplsgroupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700166 } else {
167 // outer group is L3Unicast
168 int l3unicastIndex = getNextAvailableIndex();
169 int l3groupId = L3_UNICAST_TYPE | (TYPE_MASK & l3unicastIndex);
170 final GroupKey l3groupkey = new DefaultGroupKey(
Pier Ventre140a8942016-11-02 07:26:38 -0700171 Ofdpa2Pipeline.appKryo.serialize(l3unicastIndex));
Yi Tsengfa394de2017-02-01 11:26:40 -0800172 outerTtb.group(new GroupId(l2groupId));
Charles Chan425854b2016-04-11 15:32:12 -0700173 // create the l3unicast group description to wait for the
174 // l2 interface group to be processed
175 GroupBucket l3unicastGroupBucket =
176 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
177 outerGrpDesc = new DefaultGroupDescription(
178 deviceId,
179 GroupDescription.Type.INDIRECT,
180 new GroupBuckets(Collections.singletonList(
181 l3unicastGroupBucket)),
182 l3groupkey,
183 l3groupId,
184 appId);
185 log.debug("Trying L3Unicast: device:{} gid:{} gkey:{} nextid:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700186 deviceId, Integer.toHexString(l3groupId),
187 l3groupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700188 }
189
190 // store l2groupkey with the groupChainElem for the outer-group that depends on it
Yi Tsengef19de12017-04-24 11:33:05 -0700191 GroupChainElem gce = new GroupChainElem(outerGrpDesc,
192 1,
193 false,
194 deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700195 updatePendingGroups(l2groupkey, gce);
196
197 // create group description for the inner l2interfacegroup
198 GroupBucket l2InterfaceGroupBucket =
199 DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build());
200 GroupDescription l2groupDescription =
201 new DefaultGroupDescription(
202 deviceId,
203 GroupDescription.Type.INDIRECT,
204 new GroupBuckets(Collections.singletonList(
205 l2InterfaceGroupBucket)),
206 l2groupkey,
207 l2groupId,
208 appId);
209 log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700210 deviceId, Integer.toHexString(l2groupId),
211 l2groupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700212 return new GroupInfo(l2groupDescription, outerGrpDesc);
213 }
Pier Ventre140a8942016-11-02 07:26:38 -0700214
Pier Ventre140a8942016-11-02 07:26:38 -0700215 /**
216 * In OFDPA2 we do not support the MPLS-ECMP, while we do in
217 * CPQD implementation.
218 *
219 * @param nextObjective the hashed next objective to support.
220 */
221 @Override
222 protected void processHashedNextObjective(NextObjective nextObjective) {
223 // The case for MPLS-ECMP. For now, we try to create a MPLS-ECMP for
224 // the transport of a VPWS. The necessary info are contained in the
225 // meta selector. In particular we are looking for the case of BoS==False;
226 TrafficSelector metaSelector = nextObjective.meta();
Yi Tsengef19de12017-04-24 11:33:05 -0700227 if (metaSelector != null && Ofdpa2Pipeline.isNotMplsBos(metaSelector)) {
Pier Ventre140a8942016-11-02 07:26:38 -0700228 // storage for all group keys in the chain of groups created
229 List<Deque<GroupKey>> allGroupKeys = new ArrayList<>();
230 List<GroupInfo> unsentGroups = new ArrayList<>();
231 createHashBucketChains(nextObjective, allGroupKeys, unsentGroups);
232 // now we can create the outermost MPLS ECMP group
233 List<GroupBucket> mplsEcmpGroupBuckets = new ArrayList<>();
234 for (GroupInfo gi : unsentGroups) {
235 // create ECMP bucket to point to the outer group
236 TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder();
Yi Tsengef19de12017-04-24 11:33:05 -0700237 ttb.group(new GroupId(gi.nextGroupDesc().givenGroupId()));
Pier Ventre140a8942016-11-02 07:26:38 -0700238 GroupBucket sbucket = DefaultGroupBucket
239 .createSelectGroupBucket(ttb.build());
240 mplsEcmpGroupBuckets.add(sbucket);
241 }
242 int mplsEcmpIndex = getNextAvailableIndex();
Yi Tsengef19de12017-04-24 11:33:05 -0700243 int mplsEcmpGroupId = makeMplsForwardingGroupId(OfdpaMplsGroupSubType.MPLS_ECMP, mplsEcmpIndex);
Pier Ventre140a8942016-11-02 07:26:38 -0700244 GroupKey mplsEmpGroupKey = new DefaultGroupKey(
245 Ofdpa2Pipeline.appKryo.serialize(mplsEcmpIndex)
246 );
247 GroupDescription mplsEcmpGroupDesc = new DefaultGroupDescription(
248 deviceId,
249 GroupDescription.Type.SELECT,
250 new GroupBuckets(mplsEcmpGroupBuckets),
251 mplsEmpGroupKey,
252 mplsEcmpGroupId,
253 nextObjective.appId()
254 );
255 GroupChainElem mplsEcmpGce = new GroupChainElem(mplsEcmpGroupDesc,
256 mplsEcmpGroupBuckets.size(),
Yi Tsengef19de12017-04-24 11:33:05 -0700257 false,
258 deviceId);
Pier Ventre140a8942016-11-02 07:26:38 -0700259
260 // create objects for local and distributed storage
261 allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(mplsEmpGroupKey));
262 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObjective);
263
264 // store mplsEcmpGroupKey with the ofdpaGroupChain for the nextObjective
265 // that depends on it
266 updatePendingNextObjective(mplsEmpGroupKey, ofdpaGrp);
267
268 log.debug("Trying MPLS-ECMP: device:{} gid:{} gkey:{} nextId:{}",
269 deviceId, Integer.toHexString(mplsEcmpGroupId),
270 mplsEmpGroupKey, nextObjective.id());
271
272 // finally we are ready to send the innermost groups
273 for (GroupInfo gi : unsentGroups) {
274 log.debug("Sending innermost group {} in group chain on device {} ",
Yi Tsengef19de12017-04-24 11:33:05 -0700275 Integer.toHexString(gi.innerMostGroupDesc().givenGroupId()), deviceId);
276 updatePendingGroups(gi.nextGroupDesc().appCookie(), mplsEcmpGce);
277 groupService.addGroup(gi.innerMostGroupDesc());
Pier Ventre140a8942016-11-02 07:26:38 -0700278 }
279 return;
280 }
281 super.processHashedNextObjective(nextObjective);
282 }
Charles Chan425854b2016-04-11 15:32:12 -0700283}