blob: 8c07deac84750cf4387d49895cd722da1aec0a37 [file] [log] [blame]
Charles Chan425854b2016-04-11 15:32:12 -07001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
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
17package org.onosproject.driver.pipeline;
18
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
Pier Ventre140a8942016-11-02 07:26:38 -070046import static org.onosproject.driver.pipeline.Ofdpa2GroupHandler.OfdpaMplsGroupSubType.MPLS_ECMP;
47import static org.onosproject.driver.pipeline.Ofdpa2Pipeline.isNotMplsBos;
Charles Chan425854b2016-04-11 15:32:12 -070048import static org.slf4j.LoggerFactory.getLogger;
49
50/**
51 * Group handler for CpqD OFDPA pipeline.
52 */
53public class CpqdOfdpa2GroupHandler extends Ofdpa2GroupHandler {
54 private final Logger log = getLogger(getClass());
55
56 @Override
57 protected GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId,
58 ApplicationId appId, boolean mpls,
59 TrafficSelector meta) {
60 // for the l2interface group, get vlan and port info
61 // for the outer group, get the src/dst mac, and vlan info
62 TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
63 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
64 VlanId vlanid = null;
65 long portNum = 0;
66 boolean setVlan = false, popVlan = false;
67 MacAddress srcMac = MacAddress.ZERO;
68 MacAddress dstMac = MacAddress.ZERO;
69 for (Instruction ins : treatment.allInstructions()) {
70 if (ins.type() == Instruction.Type.L2MODIFICATION) {
71 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
72 switch (l2ins.subtype()) {
73 case ETH_DST:
74 dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
75 outerTtb.setEthDst(dstMac);
76 break;
77 case ETH_SRC:
78 srcMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
79 outerTtb.setEthSrc(srcMac);
80 break;
81 case VLAN_ID:
82 vlanid = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId();
83 outerTtb.setVlanId(vlanid);
84 setVlan = true;
85 break;
86 case VLAN_POP:
87 innerTtb.popVlan();
88 popVlan = true;
89 break;
90 case DEC_MPLS_TTL:
91 case MPLS_LABEL:
92 case MPLS_POP:
93 case MPLS_PUSH:
94 case VLAN_PCP:
95 case VLAN_PUSH:
96 default:
97 break;
98 }
99 } else if (ins.type() == Instruction.Type.OUTPUT) {
100 portNum = ((Instructions.OutputInstruction) ins).port().toLong();
101 innerTtb.add(ins);
102 } else {
103 log.warn("Driver does not handle this type of TrafficTreatment"
Pier Ventre140a8942016-11-02 07:26:38 -0700104 + " instruction in nextObjectives: {}", ins.type());
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
192 GroupChainElem gce = new GroupChainElem(outerGrpDesc, 1, false);
193 updatePendingGroups(l2groupkey, gce);
194
195 // create group description for the inner l2interfacegroup
196 GroupBucket l2InterfaceGroupBucket =
197 DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build());
198 GroupDescription l2groupDescription =
199 new DefaultGroupDescription(
200 deviceId,
201 GroupDescription.Type.INDIRECT,
202 new GroupBuckets(Collections.singletonList(
203 l2InterfaceGroupBucket)),
204 l2groupkey,
205 l2groupId,
206 appId);
207 log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}",
Pier Ventre140a8942016-11-02 07:26:38 -0700208 deviceId, Integer.toHexString(l2groupId),
209 l2groupkey, nextId);
Charles Chan425854b2016-04-11 15:32:12 -0700210 return new GroupInfo(l2groupDescription, outerGrpDesc);
211 }
Pier Ventre140a8942016-11-02 07:26:38 -0700212
213 @Override
214 public boolean verifyHashedNextObjective(NextObjective nextObjective) {
215 return true;
216 }
217
218 /**
219 * In OFDPA2 we do not support the MPLS-ECMP, while we do in
220 * CPQD implementation.
221 *
222 * @param nextObjective the hashed next objective to support.
223 */
224 @Override
225 protected void processHashedNextObjective(NextObjective nextObjective) {
226 // The case for MPLS-ECMP. For now, we try to create a MPLS-ECMP for
227 // the transport of a VPWS. The necessary info are contained in the
228 // meta selector. In particular we are looking for the case of BoS==False;
229 TrafficSelector metaSelector = nextObjective.meta();
230 if (metaSelector != null && isNotMplsBos(metaSelector)) {
231 // storage for all group keys in the chain of groups created
232 List<Deque<GroupKey>> allGroupKeys = new ArrayList<>();
233 List<GroupInfo> unsentGroups = new ArrayList<>();
234 createHashBucketChains(nextObjective, allGroupKeys, unsentGroups);
235 // now we can create the outermost MPLS ECMP group
236 List<GroupBucket> mplsEcmpGroupBuckets = new ArrayList<>();
237 for (GroupInfo gi : unsentGroups) {
238 // create ECMP bucket to point to the outer group
239 TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder();
Yi Tsengfa394de2017-02-01 11:26:40 -0800240 ttb.group(new GroupId(gi.getNextGroupDesc().givenGroupId()));
Pier Ventre140a8942016-11-02 07:26:38 -0700241 GroupBucket sbucket = DefaultGroupBucket
242 .createSelectGroupBucket(ttb.build());
243 mplsEcmpGroupBuckets.add(sbucket);
244 }
245 int mplsEcmpIndex = getNextAvailableIndex();
246 int mplsEcmpGroupId = makeMplsForwardingGroupId(MPLS_ECMP, mplsEcmpIndex);
247 GroupKey mplsEmpGroupKey = new DefaultGroupKey(
248 Ofdpa2Pipeline.appKryo.serialize(mplsEcmpIndex)
249 );
250 GroupDescription mplsEcmpGroupDesc = new DefaultGroupDescription(
251 deviceId,
252 GroupDescription.Type.SELECT,
253 new GroupBuckets(mplsEcmpGroupBuckets),
254 mplsEmpGroupKey,
255 mplsEcmpGroupId,
256 nextObjective.appId()
257 );
258 GroupChainElem mplsEcmpGce = new GroupChainElem(mplsEcmpGroupDesc,
259 mplsEcmpGroupBuckets.size(),
260 false);
261
262 // create objects for local and distributed storage
263 allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(mplsEmpGroupKey));
264 OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObjective);
265
266 // store mplsEcmpGroupKey with the ofdpaGroupChain for the nextObjective
267 // that depends on it
268 updatePendingNextObjective(mplsEmpGroupKey, ofdpaGrp);
269
270 log.debug("Trying MPLS-ECMP: device:{} gid:{} gkey:{} nextId:{}",
271 deviceId, Integer.toHexString(mplsEcmpGroupId),
272 mplsEmpGroupKey, nextObjective.id());
273
274 // finally we are ready to send the innermost groups
275 for (GroupInfo gi : unsentGroups) {
276 log.debug("Sending innermost group {} in group chain on device {} ",
277 Integer.toHexString(gi.getInnerMostGroupDesc().givenGroupId()), deviceId);
278 updatePendingGroups(gi.getNextGroupDesc().appCookie(), mplsEcmpGce);
279 groupService.addGroup(gi.getInnerMostGroupDesc());
280 }
281 return;
282 }
283 super.processHashedNextObjective(nextObjective);
284 }
Charles Chan425854b2016-04-11 15:32:12 -0700285}