blob: 078e120cae0ff4772628dc03462d5f8d77af0313 [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 {
Saurav Dasa4020382018-02-14 14:14:54 -0800102 log.debug("Driver does not handle this type of TrafficTreatment"
103 + " instruction in l2l3chain: {} - {}", ins.type(),
104 ins);
Charles Chan425854b2016-04-11 15:32:12 -0700105 }
106 }
107
108 if (vlanid == null && meta != null) {
109 // use metadata if available
110 Criterion vidCriterion = meta.getCriterion(Criterion.Type.VLAN_VID);
111 if (vidCriterion != null) {
112 vlanid = ((VlanIdCriterion) vidCriterion).vlanId();
113 }
114 // if vlan is not set, use the vlan in metadata for outerTtb
115 if (vlanid != null && !setVlan) {
116 outerTtb.setVlanId(vlanid);
117 }
118 }
119
120 if (vlanid == null) {
121 log.error("Driver cannot process an L2/L3 group chain without "
Pier Ventre140a8942016-11-02 07:26:38 -0700122 + "egress vlan information for dev: {} port:{}",
123 deviceId, portNum);
Charles Chan425854b2016-04-11 15:32:12 -0700124 return null;
125 }
126
127 if (!setVlan && !popVlan) {
128 // untagged outgoing port
129 TrafficTreatment.Builder temp = DefaultTrafficTreatment.builder();
130 temp.popVlan();
131 innerTtb.build().allInstructions().forEach(i -> temp.add(i));
132 innerTtb = temp;
133 }
134
135 // assemble information for ofdpa l2interface group
136 int l2groupId = L2_INTERFACE_TYPE | (vlanid.toShort() << 16) | (int) portNum;
137 // a globally unique groupkey that is different for ports in the same device,
138 // but different for the same portnumber on different devices. Also different
139 // for the various group-types created out of the same next objective.
140 int l2gk = l2InterfaceGroupKey(deviceId, vlanid, portNum);
141 final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2gk));
142
143 // assemble information for outer group
144 GroupDescription outerGrpDesc = null;
145 if (mpls) {
146 // outer group is MPLSInteface
147 int mplsInterfaceIndex = getNextAvailableIndex();
148 int mplsgroupId = MPLS_INTERFACE_TYPE | (SUBTYPE_MASK & mplsInterfaceIndex);
149 final GroupKey mplsgroupkey = new DefaultGroupKey(
Pier Ventre140a8942016-11-02 07:26:38 -0700150 Ofdpa2Pipeline.appKryo.serialize(mplsInterfaceIndex));
Yi Tsengfa394de2017-02-01 11:26:40 -0800151 outerTtb.group(new GroupId(l2groupId));
Charles Chan425854b2016-04-11 15:32:12 -0700152 // create the mpls-interface group description to wait for the
153 // l2 interface group to be processed
154 GroupBucket mplsinterfaceGroupBucket =
155 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
156 outerGrpDesc = new DefaultGroupDescription(
157 deviceId,
158 GroupDescription.Type.INDIRECT,
159 new GroupBuckets(Collections.singletonList(
160 mplsinterfaceGroupBucket)),
161 mplsgroupkey,
162 mplsgroupId,
163 appId);
164 log.debug("Trying MPLS-Interface: device:{} gid:{} gkey:{} nextid:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700165 deviceId, Integer.toHexString(mplsgroupId),
166 mplsgroupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700167 } else {
168 // outer group is L3Unicast
169 int l3unicastIndex = getNextAvailableIndex();
170 int l3groupId = L3_UNICAST_TYPE | (TYPE_MASK & l3unicastIndex);
171 final GroupKey l3groupkey = new DefaultGroupKey(
Pier Ventre140a8942016-11-02 07:26:38 -0700172 Ofdpa2Pipeline.appKryo.serialize(l3unicastIndex));
Yi Tsengfa394de2017-02-01 11:26:40 -0800173 outerTtb.group(new GroupId(l2groupId));
Charles Chan425854b2016-04-11 15:32:12 -0700174 // create the l3unicast group description to wait for the
175 // l2 interface group to be processed
176 GroupBucket l3unicastGroupBucket =
177 DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
178 outerGrpDesc = new DefaultGroupDescription(
179 deviceId,
180 GroupDescription.Type.INDIRECT,
181 new GroupBuckets(Collections.singletonList(
182 l3unicastGroupBucket)),
183 l3groupkey,
184 l3groupId,
185 appId);
186 log.debug("Trying L3Unicast: device:{} gid:{} gkey:{} nextid:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700187 deviceId, Integer.toHexString(l3groupId),
188 l3groupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700189 }
190
191 // store l2groupkey with the groupChainElem for the outer-group that depends on it
Yi Tsengef19de12017-04-24 11:33:05 -0700192 GroupChainElem gce = new GroupChainElem(outerGrpDesc,
193 1,
194 false,
195 deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700196 updatePendingGroups(l2groupkey, gce);
197
198 // create group description for the inner l2interfacegroup
199 GroupBucket l2InterfaceGroupBucket =
200 DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build());
201 GroupDescription l2groupDescription =
202 new DefaultGroupDescription(
203 deviceId,
204 GroupDescription.Type.INDIRECT,
205 new GroupBuckets(Collections.singletonList(
206 l2InterfaceGroupBucket)),
207 l2groupkey,
208 l2groupId,
209 appId);
210 log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700211 deviceId, Integer.toHexString(l2groupId),
212 l2groupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700213 return new GroupInfo(l2groupDescription, outerGrpDesc);
214 }
Pier Ventre140a8942016-11-02 07:26:38 -0700215
Pier Ventre140a8942016-11-02 07:26:38 -0700216 /**
217 * In OFDPA2 we do not support the MPLS-ECMP, while we do in
218 * CPQD implementation.
219 *
220 * @param nextObjective the hashed next objective to support.
221 */
222 @Override
223 protected void processHashedNextObjective(NextObjective nextObjective) {
224 // The case for MPLS-ECMP. For now, we try to create a MPLS-ECMP for
225 // the transport of a VPWS. The necessary info are contained in the
226 // meta selector. In particular we are looking for the case of BoS==False;
227 TrafficSelector metaSelector = nextObjective.meta();
Yi Tsengef19de12017-04-24 11:33:05 -0700228 if (metaSelector != null && Ofdpa2Pipeline.isNotMplsBos(metaSelector)) {
Pier Ventre140a8942016-11-02 07:26:38 -0700229 // storage for all group keys in the chain of groups created
230 List<Deque<GroupKey>> allGroupKeys = new ArrayList<>();
231 List<GroupInfo> unsentGroups = new ArrayList<>();
232 createHashBucketChains(nextObjective, allGroupKeys, unsentGroups);
233 // now we can create the outermost MPLS ECMP group
234 List<GroupBucket> mplsEcmpGroupBuckets = new ArrayList<>();
235 for (GroupInfo gi : unsentGroups) {
236 // create ECMP bucket to point to the outer group
237 TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder();
Yi Tsengef19de12017-04-24 11:33:05 -0700238 ttb.group(new GroupId(gi.nextGroupDesc().givenGroupId()));
Pier Ventre140a8942016-11-02 07:26:38 -0700239 GroupBucket sbucket = DefaultGroupBucket
240 .createSelectGroupBucket(ttb.build());
241 mplsEcmpGroupBuckets.add(sbucket);
242 }
243 int mplsEcmpIndex = getNextAvailableIndex();
Yi Tsengef19de12017-04-24 11:33:05 -0700244 int mplsEcmpGroupId = makeMplsForwardingGroupId(OfdpaMplsGroupSubType.MPLS_ECMP, mplsEcmpIndex);
Pier Ventre140a8942016-11-02 07:26:38 -0700245 GroupKey mplsEmpGroupKey = new DefaultGroupKey(
246 Ofdpa2Pipeline.appKryo.serialize(mplsEcmpIndex)
247 );
248 GroupDescription mplsEcmpGroupDesc = new DefaultGroupDescription(
249 deviceId,
250 GroupDescription.Type.SELECT,
251 new GroupBuckets(mplsEcmpGroupBuckets),
252 mplsEmpGroupKey,
253 mplsEcmpGroupId,
254 nextObjective.appId()
255 );
256 GroupChainElem mplsEcmpGce = new GroupChainElem(mplsEcmpGroupDesc,
257 mplsEcmpGroupBuckets.size(),
Yi Tsengef19de12017-04-24 11:33:05 -0700258 false,
259 deviceId);
Pier Ventre140a8942016-11-02 07:26:38 -0700260
261 // create objects for local and distributed storage
262 allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(mplsEmpGroupKey));
263 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObjective);
264
265 // store mplsEcmpGroupKey with the ofdpaGroupChain for the nextObjective
266 // that depends on it
267 updatePendingNextObjective(mplsEmpGroupKey, ofdpaGrp);
268
269 log.debug("Trying MPLS-ECMP: device:{} gid:{} gkey:{} nextId:{}",
270 deviceId, Integer.toHexString(mplsEcmpGroupId),
271 mplsEmpGroupKey, nextObjective.id());
272
273 // finally we are ready to send the innermost groups
274 for (GroupInfo gi : unsentGroups) {
275 log.debug("Sending innermost group {} in group chain on device {} ",
Yi Tsengef19de12017-04-24 11:33:05 -0700276 Integer.toHexString(gi.innerMostGroupDesc().givenGroupId()), deviceId);
277 updatePendingGroups(gi.nextGroupDesc().appCookie(), mplsEcmpGce);
278 groupService.addGroup(gi.innerMostGroupDesc());
Pier Ventre140a8942016-11-02 07:26:38 -0700279 }
280 return;
281 }
282 super.processHashedNextObjective(nextObjective);
283 }
Charles Chan425854b2016-04-11 15:32:12 -0700284}