blob: 980d1f6d9818dab8c09c546173e784ed649ca306 [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Thomas Vachuska58de4162015-09-10 16:15:33 -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 */
Yi Tsengef19de12017-04-24 11:33:05 -070016package org.onosproject.driver.pipeline.ofdpa;
Saurav Das558afec2015-05-31 17:12:48 -070017
Charles Chan5270ed02016-01-30 23:22:37 -080018import com.google.common.collect.ImmutableList;
Charles Chan5b9df8d2016-03-28 22:21:40 -070019import com.google.common.collect.ImmutableSet;
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -070020import org.onlab.packet.EthType;
Saurav Das8a0732e2015-11-20 15:27:53 -080021import org.onlab.packet.Ethernet;
Julia Ferguson65428c32017-08-10 18:15:24 +000022import org.onlab.packet.IpAddress;
Flavio Castroe10fa242016-01-15 12:43:51 -080023import org.onlab.packet.IpPrefix;
Charles Chand57552d2018-03-02 15:41:41 -080024import org.onlab.packet.MacAddress;
Saurav Das2857f382015-11-03 14:39:27 -080025import org.onlab.packet.VlanId;
26import org.onosproject.core.ApplicationId;
Yi Tsengfa394de2017-02-01 11:26:40 -080027import org.onosproject.core.GroupId;
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -070028import org.onosproject.net.DeviceId;
Saurav Das2857f382015-11-03 14:39:27 -080029import org.onosproject.net.Port;
30import org.onosproject.net.PortNumber;
Saurav Das8a0732e2015-11-20 15:27:53 -080031import org.onosproject.net.behaviour.NextGroup;
Charles Chan425854b2016-04-11 15:32:12 -070032import org.onosproject.net.behaviour.PipelinerContext;
Saurav Das558afec2015-05-31 17:12:48 -070033import org.onosproject.net.flow.DefaultFlowRule;
34import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.FlowRule;
37import org.onosproject.net.flow.FlowRuleOperations;
38import org.onosproject.net.flow.FlowRuleOperationsContext;
39import org.onosproject.net.flow.TrafficSelector;
40import org.onosproject.net.flow.TrafficTreatment;
Saurav Das4ce45962015-11-24 23:21:05 -080041import org.onosproject.net.flow.criteria.Criteria;
Saurav Das8a0732e2015-11-20 15:27:53 -080042import org.onosproject.net.flow.criteria.Criterion;
Saurav Das4ce45962015-11-24 23:21:05 -080043import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080044import org.onosproject.net.flow.criteria.EthTypeCriterion;
45import org.onosproject.net.flow.criteria.IPCriterion;
Pier Ventree0ae7a32016-11-23 09:57:42 -080046import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion;
47import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080048import org.onosproject.net.flow.criteria.MplsBosCriterion;
49import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das2857f382015-11-03 14:39:27 -080050import org.onosproject.net.flow.criteria.PortCriterion;
51import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080052import org.onosproject.net.flow.instructions.Instruction;
Saurav Das52025962016-01-28 22:30:01 -080053import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Charles Chan3fe71712018-06-15 18:54:18 -070054import org.onosproject.net.flow.instructions.Instructions.NoActionInstruction;
Charles Chan40132b32017-01-22 00:19:37 -080055import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Saurav Das8a0732e2015-11-20 15:27:53 -080056import org.onosproject.net.flowobjective.ForwardingObjective;
57import org.onosproject.net.flowobjective.ObjectiveError;
Charles Chan0f43e472017-02-14 14:00:16 -080058import org.onosproject.net.group.DefaultGroupBucket;
59import org.onosproject.net.group.DefaultGroupDescription;
60import org.onosproject.net.group.DefaultGroupKey;
Saurav Das8a0732e2015-11-20 15:27:53 -080061import org.onosproject.net.group.Group;
Charles Chan0f43e472017-02-14 14:00:16 -080062import org.onosproject.net.group.GroupBucket;
63import org.onosproject.net.group.GroupBuckets;
64import org.onosproject.net.group.GroupDescription;
Saurav Das8a0732e2015-11-20 15:27:53 -080065import org.onosproject.net.group.GroupKey;
Charles Chanf57a8252016-06-29 19:12:37 -070066import org.onosproject.net.packet.PacketPriority;
Saurav Das558afec2015-05-31 17:12:48 -070067import org.slf4j.Logger;
68
Jonathan Hart855179c2016-04-26 07:40:04 -070069import java.util.ArrayList;
70import java.util.Collection;
71import java.util.Collections;
72import java.util.Deque;
73import java.util.List;
Charles Chan0f43e472017-02-14 14:00:16 -080074import java.util.Objects;
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -070075import java.util.Queue;
76import java.util.concurrent.ConcurrentLinkedQueue;
77import java.util.concurrent.Executors;
78import java.util.concurrent.ScheduledExecutorService;
79import java.util.concurrent.TimeUnit;
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -070080import java.util.concurrent.locks.ReentrantLock;
Jonathan Hart855179c2016-04-26 07:40:04 -070081
Pier Ventree0ae7a32016-11-23 09:57:42 -080082import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Charles Chand05f54b2017-02-13 11:56:54 -080083import static org.onlab.packet.MacAddress.BROADCAST;
84import static org.onlab.packet.MacAddress.NONE;
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -070085import static org.onlab.util.Tools.groupedThreads;
Yi Tsengef19de12017-04-24 11:33:05 -070086import static org.onosproject.driver.pipeline.ofdpa.OfdpaGroupHandlerUtility.*;
pier5c817582019-04-17 17:05:08 +020087import static org.onosproject.driver.pipeline.ofdpa.OfdpaPipelineUtility.*;
Jonathan Hart855179c2016-04-26 07:40:04 -070088import static org.slf4j.LoggerFactory.getLogger;
89
Saurav Das558afec2015-05-31 17:12:48 -070090
91/**
Charles Chan40132b32017-01-22 00:19:37 -080092 * Driver for software switch emulation of the OFDPA pipeline.
Saurav Das52025962016-01-28 22:30:01 -080093 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
94 * does not handle vlan tags and mpls labels simultaneously, which requires us
95 * to do some workarounds in the driver. This driver is meant for the use of
96 * the cpqd switch when MPLS is required. As a result this driver works only
97 * on incoming untagged packets.
Saurav Das558afec2015-05-31 17:12:48 -070098 */
Charles Chan361154b2016-03-24 10:23:39 -070099public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -0700100
101 private final Logger log = getLogger(getClass());
102
Charles Chan40132b32017-01-22 00:19:37 -0800103 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800104 * Table that determines whether VLAN is popped before punting to controller.
105 * <p>
106 * This is a non-OFDPA table to emulate OFDPA packet in behavior.
107 * VLAN will be popped before punting if the VLAN is internally assigned.
108 * <p>
109 * Also note that 63 is the max table number in CpqD.
110 */
111 private static final int PUNT_TABLE = 63;
112
113 /**
114 * A static indirect group that pop vlan and punt to controller.
115 * <p>
116 * The purpose of using a group instead of immediate action is that this
117 * won't affect another copy on the data plane when write action exists.
118 */
119 private static final int POP_VLAN_PUNT_GROUP_ID = 0xc0000000;
120
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700121 /**
122 * Executor for group checker thread that checks pop vlan punt group.
123 */
124 private ScheduledExecutorService groupChecker;
125
126 /**
127 * Queue for passing pop vlan punt group flow rules to the GroupChecker thread.
128 */
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700129 private Queue<FlowRule> flowRuleQueue;
130
131 /**
132 * Lock used in synchronizing driver thread with groupCheckerThread.
133 */
134 private ReentrantLock groupCheckerLock;
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700135
Charles Chan053b1cb2017-03-22 16:56:35 -0700136 @Override
137 protected boolean requireVlanExtensions() {
138 return false;
139 }
140
Harshada Chaundkarb73d5d62019-08-05 15:33:30 +0000141 @Override
142 protected boolean requireEthType() {
143 return false;
144 }
145
Charles Chan0f43e472017-02-14 14:00:16 -0800146 /**
Charles Chan40132b32017-01-22 00:19:37 -0800147 * Determines whether this pipeline support copy ttl instructions or not.
148 *
149 * @return true if copy ttl instructions are supported
150 */
151 protected boolean supportCopyTtl() {
152 return true;
153 }
154
Charles Chan0f43e472017-02-14 14:00:16 -0800155 /**
156 * Determines whether this pipeline support push mpls to vlan-tagged packets or not.
157 * <p>
158 * If not support, pop vlan before push entering unicast and mpls table.
159 * Side effect: HostService learns redundant hosts with same MAC but
160 * different VLAN. No known side effect on the network reachability.
161 *
162 * @return true if push mpls to vlan-tagged packets is supported
163 */
164 protected boolean supportTaggedMpls() {
165 return false;
166 }
167
168 /**
169 * Determines whether this pipeline support punt action in group bucket.
170 *
171 * @return true if punt action in group bucket is supported
172 */
173 protected boolean supportPuntGroup() {
174 return false;
175 }
176
Charles Chan425854b2016-04-11 15:32:12 -0700177 @Override
Charles Chan40132b32017-01-22 00:19:37 -0800178 protected void initDriverId() {
Charles Chan425854b2016-04-11 15:32:12 -0700179 driverId = coreService.registerApplication(
180 "org.onosproject.driver.CpqdOfdpa2Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -0800181 }
Charles Chan425854b2016-04-11 15:32:12 -0700182
Charles Chan40132b32017-01-22 00:19:37 -0800183 @Override
184 protected void initGroupHander(PipelinerContext context) {
pier95e62512020-03-20 11:00:38 +0100185 // Terminate internal references
186 // We are terminating the references here
187 // because when the device is offline the apps
188 // are still sending flowobjectives
189 if (groupHandler != null) {
190 groupHandler.terminate();
191 }
Charles Chan40132b32017-01-22 00:19:37 -0800192 groupHandler = new CpqdOfdpa2GroupHandler();
193 groupHandler.init(deviceId, context);
Charles Chan425854b2016-04-11 15:32:12 -0700194 }
195
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700196 @Override
197 public void init(DeviceId deviceId, PipelinerContext context) {
pier20511962020-05-11 13:49:37 +0200198 if (supportPuntGroup()) {
199 // Terminate internal references
200 // We are terminating the references here
201 // because when the device is offline the apps
202 // are still sending flowobjectives
203 if (groupChecker != null) {
204 groupChecker.shutdown();
pier95e62512020-03-20 11:00:38 +0100205 }
pier20511962020-05-11 13:49:37 +0200206 // create a new executor at each init and a new empty queue
207 groupChecker = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/driver",
208 "cpqd-ofdpa-%d", log));
209 if (flowRuleQueue != null) {
210 flowRuleQueue.clear();
piera3b186e2020-02-28 09:24:11 +0100211 }
pier20511962020-05-11 13:49:37 +0200212 flowRuleQueue = new ConcurrentLinkedQueue<>();
213 groupCheckerLock = new ReentrantLock();
214 groupChecker.scheduleAtFixedRate(new PopVlanPuntGroupChecker(), 20, 50, TimeUnit.MILLISECONDS);
215 super.init(deviceId, context);
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700216 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700217 }
Saurav Das4ce45962015-11-24 23:21:05 -0800218 /*
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700219 * Cpqd emulation does not require the non OF-standard rules for
220 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800221 *
222 * (non-Javadoc)
223 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
224 */
Saurav Das558afec2015-05-31 17:12:48 -0700225 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800226 protected List<List<FlowRule>> processVlanIdFilter(PortCriterion portCriterion,
pierb2f71142019-06-10 17:10:26 +0200227 VlanIdCriterion vidCriterion,
228 VlanId assignedVlan,
229 ApplicationId applicationId,
230 boolean install) {
Charles Chan79769232016-07-05 16:34:39 -0700231 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800232 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
233 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
234 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800235 treatment.transition(TMAC_TABLE);
236
Saurav Das2857f382015-11-03 14:39:27 -0800237 if (vidCriterion.vlanId() == VlanId.NONE) {
238 // untagged packets are assigned vlans
239 treatment.pushVlan().setVlanId(assignedVlan);
Pier3cc7e662018-03-07 11:42:50 +0100240 } else if (!vidCriterion.vlanId().equals(assignedVlan)) {
241 // Rewrite with assigned vlans
242 treatment.setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800243 }
Saurav Das2857f382015-11-03 14:39:27 -0800244
245 // ofdpa cannot match on ALL portnumber, so we need to use separate
246 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800247 List<PortNumber> portnums = new ArrayList<>();
Ray Milkey94542b02018-05-10 12:42:51 -0700248 if (portCriterion != null) {
249 if (portCriterion.port() == PortNumber.ALL) {
250 for (Port port : deviceService.getPorts(deviceId)) {
251 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
252 portnums.add(port.number());
253 }
Saurav Das2857f382015-11-03 14:39:27 -0800254 }
Ray Milkey94542b02018-05-10 12:42:51 -0700255 } else {
256 portnums.add(portCriterion.port());
Saurav Das2857f382015-11-03 14:39:27 -0800257 }
Saurav Das2857f382015-11-03 14:39:27 -0800258 }
Saurav Das4f980082015-11-05 13:39:15 -0800259
Saurav Das2857f382015-11-03 14:39:27 -0800260 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800261 // NOTE: Emulating OFDPA behavior by popping off internal assigned
262 // VLAN before sending to controller
263 if (supportPuntGroup() && vidCriterion.vlanId() == VlanId.NONE) {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700264 try {
265 groupCheckerLock.lock();
266 if (flowRuleQueue == null) {
267 // this means that the group has been created
268 // and that groupChecker has destroyed the queue
269 log.debug("Installing punt table rule for untagged port {} and vlan {}.",
270 pnum, assignedVlan);
271 rules.add(buildPuntTableRule(pnum, assignedVlan));
272 } else {
273 // The VLAN punt group may be held back due to device initial audit.
274 // In that case, we queue all punt table flow until the group has been created.
275 log.debug("popVlanPuntGroup not found in dev:{}, queueing this flow rule.", deviceId);
276 flowRuleQueue.add(buildPuntTableRule(pnum, assignedVlan));
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700277 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700278 } finally {
279 groupCheckerLock.unlock();
Charles Chan0f43e472017-02-14 14:00:16 -0800280 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700281 } else if (vidCriterion.vlanId() != VlanId.NONE) {
282 // for tagged ports just forward to the controller
283 log.debug("Installing punt rule for tagged port {} and vlan {}.", pnum, vidCriterion.vlanId());
284 rules.add(buildPuntTableRuleTagged(pnum, vidCriterion.vlanId()));
Charles Chan0f43e472017-02-14 14:00:16 -0800285 }
286
Saurav Das4f980082015-11-05 13:39:15 -0800287 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800288 selector.matchInPort(pnum);
289 FlowRule rule = DefaultFlowRule.builder()
290 .forDevice(deviceId)
291 .withSelector(selector.build())
292 .withTreatment(treatment.build())
293 .withPriority(DEFAULT_PRIORITY)
294 .fromApp(applicationId)
295 .makePermanent()
296 .forTable(VLAN_TABLE).build();
297 rules.add(rule);
298 }
Charles Chanf57a8252016-06-29 19:12:37 -0700299
Charles Chan206506b2018-03-02 16:43:28 -0800300 return ImmutableList.of(rules);
Saurav Das2857f382015-11-03 14:39:27 -0800301 }
302
Pier Ventree0ae7a32016-11-23 09:57:42 -0800303 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800304 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
305 * a group that pop vlan and punt.
306 *
307 * @param portNumber port number
308 * @param assignedVlan internally assigned vlan id
309 * @return punt table flow rule
310 */
311 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
312 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
313 .matchInPort(portNumber)
314 .matchVlanId(assignedVlan);
315 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
Yi Tsengfa394de2017-02-01 11:26:40 -0800316 .group(new GroupId(POP_VLAN_PUNT_GROUP_ID));
Charles Chan0f43e472017-02-14 14:00:16 -0800317
318 return DefaultFlowRule.builder()
319 .forDevice(deviceId)
320 .withSelector(sbuilder.build())
321 .withTreatment(tbuilder.build())
322 .withPriority(PacketPriority.CONTROL.priorityValue())
323 .fromApp(driverId)
324 .makePermanent()
325 .forTable(PUNT_TABLE).build();
326 }
327
328 /**
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700329 * Creates punt table entry that matches IN_PORT and VLAN_VID and forwards
330 * packet to controller tagged.
331 *
332 * @param portNumber port number
333 * @param packetVlan vlan tag of the packet
334 * @return punt table flow rule
335 */
336 private FlowRule buildPuntTableRuleTagged(PortNumber portNumber, VlanId packetVlan) {
337 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
338 .matchInPort(portNumber)
339 .matchVlanId(packetVlan);
340 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder().punt();
341
342 return DefaultFlowRule.builder()
343 .forDevice(deviceId)
344 .withSelector(sbuilder.build())
345 .withTreatment(tbuilder.build())
346 .withPriority(PacketPriority.CONTROL.priorityValue())
347 .fromApp(driverId)
348 .makePermanent()
349 .forTable(PUNT_TABLE).build();
350 }
351
352 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800353 * Builds a punt to the controller rule for the arp protocol.
Charles Chan0f43e472017-02-14 14:00:16 -0800354 * <p>
355 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
356 * pop VLAN before sending to controller disregarding whether
357 * it's an internally assigned VLAN or a natural VLAN.
358 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800359 *
360 * @param assignedVlan the internal assigned vlan id
361 * @param applicationId the application id
362 * @return the punt flow rule for the arp
363 */
364 private FlowRule buildArpPunt(VlanId assignedVlan, ApplicationId applicationId) {
365 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
366 .matchEthType(Ethernet.TYPE_ARP)
367 .matchVlanId(assignedVlan);
368 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
369 .popVlan()
370 .punt();
371
372 return DefaultFlowRule.builder()
373 .forDevice(deviceId)
374 .withSelector(sbuilder.build())
375 .withTreatment(tbuilder.build())
376 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
377 .fromApp(applicationId)
378 .makePermanent()
379 .forTable(ACL_TABLE).build();
380 }
381
382 /**
383 * Builds a punt to the controller rule for the icmp v6 messages.
Charles Chan0f43e472017-02-14 14:00:16 -0800384 * <p>
385 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
386 * pop VLAN before sending to controller disregarding whether
387 * it's an internally assigned VLAN or a natural VLAN.
388 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800389 *
390 * @param assignedVlan the internal assigned vlan id
391 * @param applicationId the application id
392 * @return the punt flow rule for the icmp v6 messages
393 */
394 private FlowRule buildIcmpV6Punt(VlanId assignedVlan, ApplicationId applicationId) {
395 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
396 .matchVlanId(assignedVlan)
397 .matchEthType(Ethernet.TYPE_IPV6)
398 .matchIPProtocol(PROTOCOL_ICMP6);
399 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
400 .popVlan()
401 .punt();
402
403 return DefaultFlowRule.builder()
404 .forDevice(deviceId)
405 .withSelector(sbuilder.build())
406 .withTreatment(tbuilder.build())
407 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
408 .fromApp(applicationId)
409 .makePermanent()
410 .forTable(ACL_TABLE).build();
411 }
412
Saurav Das4ce45962015-11-24 23:21:05 -0800413 /*
414 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
415 * Workaround requires popping off the VLAN tags in the TMAC table.
416 *
417 * (non-Javadoc)
418 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
419 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800420 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800421 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das4ce45962015-11-24 23:21:05 -0800422 EthCriterion ethCriterion,
423 VlanIdCriterion vidCriterion,
424 VlanId assignedVlan,
Charles Chand57552d2018-03-02 15:41:41 -0800425 MacAddress unicastMac,
Saurav Das4ce45962015-11-24 23:21:05 -0800426 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800427 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
428 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
429 return processEthDstOnlyFilter(ethCriterion, applicationId);
430 }
431
Charles Chan5b9df8d2016-03-28 22:21:40 -0700432 // Multicast MAC
433 if (ethCriterion.mask() != null) {
Charles Chand57552d2018-03-02 15:41:41 -0800434 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700435 }
436
Saurav Das4ce45962015-11-24 23:21:05 -0800437 //handling untagged packets via assigned VLAN
438 if (vidCriterion.vlanId() == VlanId.NONE) {
439 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
440 }
441 // ofdpa cannot match on ALL portnumber, so we need to use separate
442 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800443 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800444 if (portCriterion != null) {
445 if (portCriterion.port() == PortNumber.ALL) {
446 for (Port port : deviceService.getPorts(deviceId)) {
447 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
448 portnums.add(port.number());
449 }
Saurav Das4ce45962015-11-24 23:21:05 -0800450 }
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800451 } else {
452 portnums.add(portCriterion.port());
Saurav Das4ce45962015-11-24 23:21:05 -0800453 }
Saurav Das4ce45962015-11-24 23:21:05 -0800454 }
455
Charles Chan93090352018-03-02 13:26:22 -0800456 List<FlowRule> rules = new ArrayList<>();
Saurav Das4ce45962015-11-24 23:21:05 -0800457 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800458 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800459 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
460 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
461 selector.matchInPort(pnum);
462 selector.matchVlanId(vidCriterion.vlanId());
463 selector.matchEthType(Ethernet.TYPE_IPV4);
464 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800465 if (!supportTaggedMpls()) {
466 treatment.popVlan();
467 }
Saurav Das4ce45962015-11-24 23:21:05 -0800468 treatment.transition(UNICAST_ROUTING_TABLE);
469 FlowRule rule = DefaultFlowRule.builder()
470 .forDevice(deviceId)
471 .withSelector(selector.build())
472 .withTreatment(treatment.build())
473 .withPriority(DEFAULT_PRIORITY)
474 .fromApp(applicationId)
475 .makePermanent()
476 .forTable(TMAC_TABLE).build();
477 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800478
479 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800480 selector = DefaultTrafficSelector.builder();
481 treatment = DefaultTrafficTreatment.builder();
482 selector.matchInPort(pnum);
483 selector.matchVlanId(vidCriterion.vlanId());
484 selector.matchEthType(Ethernet.MPLS_UNICAST);
485 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800486 if (!supportTaggedMpls()) {
487 treatment.popVlan();
488 }
Saurav Das4ce45962015-11-24 23:21:05 -0800489 treatment.transition(MPLS_TABLE_0);
490 rule = DefaultFlowRule.builder()
491 .forDevice(deviceId)
492 .withSelector(selector.build())
493 .withTreatment(treatment.build())
494 .withPriority(DEFAULT_PRIORITY)
495 .fromApp(applicationId)
496 .makePermanent()
497 .forTable(TMAC_TABLE).build();
498 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800499
500 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800501 selector = DefaultTrafficSelector.builder();
502 treatment = DefaultTrafficTreatment.builder();
503 selector.matchInPort(pnum);
504 selector.matchVlanId(vidCriterion.vlanId());
505 selector.matchEthType(Ethernet.TYPE_IPV6);
506 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800507 if (!supportTaggedMpls()) {
508 treatment.popVlan();
509 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800510 treatment.transition(UNICAST_ROUTING_TABLE);
511 rule = DefaultFlowRule.builder()
512 .forDevice(deviceId)
513 .withSelector(selector.build())
514 .withTreatment(treatment.build())
515 .withPriority(DEFAULT_PRIORITY)
516 .fromApp(applicationId)
517 .makePermanent()
518 .forTable(TMAC_TABLE).build();
519 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800520 }
Charles Chan206506b2018-03-02 16:43:28 -0800521 return ImmutableList.of(rules);
Saurav Das4ce45962015-11-24 23:21:05 -0800522 }
523
Charles Chan5270ed02016-01-30 23:22:37 -0800524 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800525 protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700526 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800527 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
528 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
529 selector.matchEthType(Ethernet.TYPE_IPV4);
530 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800531 if (!supportTaggedMpls()) {
532 treatment.popVlan();
533 }
Charles Chan5270ed02016-01-30 23:22:37 -0800534 treatment.transition(UNICAST_ROUTING_TABLE);
535 FlowRule rule = DefaultFlowRule.builder()
536 .forDevice(deviceId)
537 .withSelector(selector.build())
538 .withTreatment(treatment.build())
539 .withPriority(DEFAULT_PRIORITY)
540 .fromApp(applicationId)
541 .makePermanent()
542 .forTable(TMAC_TABLE).build();
Charles Chan206506b2018-03-02 16:43:28 -0800543 return ImmutableList.of(ImmutableList.of(rule));
Charles Chan5270ed02016-01-30 23:22:37 -0800544 }
545
Saurav Das4ce45962015-11-24 23:21:05 -0800546 /*
547 * Cpqd emulation allows MPLS ecmp.
548 *
549 * (non-Javadoc)
550 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
551 */
552 @Override
553 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800554 TrafficSelector selector = fwd.selector();
555 EthTypeCriterion ethType =
556 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
557 if ((ethType == null) ||
558 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800559 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
560 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800561 log.warn("processSpecific: Unsupported forwarding objective criteria"
562 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800563 fail(fwd, ObjectiveError.UNSUPPORTED);
564 return Collections.emptySet();
565 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800566 boolean defaultRule = false;
Charles Chan93090352018-03-02 13:26:22 -0800567 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800568 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800569 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
570
Saurav Das8a0732e2015-11-20 15:27:53 -0800571 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800572 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700573 if (ipv4Dst.isMulticast()) {
574 if (ipv4Dst.prefixLength() != 32) {
575 log.warn("Multicast specific forwarding objective can only be /32");
576 fail(fwd, ObjectiveError.BADPARAMS);
577 return ImmutableSet.of();
578 }
579 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
580 if (assignedVlan == null) {
581 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
582 fail(fwd, ObjectiveError.BADPARAMS);
583 return ImmutableSet.of();
584 }
585 filteredSelector.matchVlanId(assignedVlan);
586 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
587 forTableId = MULTICAST_ROUTING_TABLE;
588 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
589 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800590 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700591 if (ipv4Dst.prefixLength() == 0) {
592 // The entire IPV4_DST field is wildcarded intentionally
593 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700594 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700595 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700596 }
597 forTableId = UNICAST_ROUTING_TABLE;
598 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
599 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800600 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800601 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
Julia Ferguson65428c32017-08-10 18:15:24 +0000602 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
603 if (ipv6Dst.isMulticast()) {
604 if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
605 log.debug("Multicast specific IPv6 forwarding objective can only be /128");
606 fail(fwd, ObjectiveError.BADPARAMS);
607 return ImmutableSet.of();
608 }
609 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
610 if (assignedVlan == null) {
611 log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
612 fail(fwd, ObjectiveError.BADPARAMS);
613 return ImmutableSet.of();
614 }
615 filteredSelector.matchVlanId(assignedVlan);
616 filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
617 forTableId = MULTICAST_ROUTING_TABLE;
618 log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
619 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
620 } else {
621 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
622 return Collections.emptyList();
623 }
624 forTableId = UNICAST_ROUTING_TABLE;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800625 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800626 } else {
627 filteredSelector
628 .matchEthType(Ethernet.MPLS_UNICAST)
629 .matchMplsLabel(((MplsCriterion)
630 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
631 MplsBosCriterion bos = (MplsBosCriterion) selector
632 .getCriterion(Criterion.Type.MPLS_BOS);
633 if (bos != null) {
634 filteredSelector.matchMplsBos(bos.mplsBos());
635 }
636 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800637 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
638 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800639 }
640
641 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
642 if (fwd.treatment() != null) {
643 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan40132b32017-01-22 00:19:37 -0800644 if (!supportCopyTtl() && i instanceof L3ModificationInstruction) {
645 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
646 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
647 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
648 continue;
649 }
650 }
Charles Chan7d10b162015-12-07 18:54:45 -0800651 /*
652 * NOTE: OF-DPA does not support immediate instruction in
653 * L3 unicast and MPLS table.
654 */
655 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800656 }
657 }
658
659 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800660 NextGroup next = getGroupForNextObjective(fwd.nextId());
661 if (next != null) {
662 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
663 // we only need the top level group's key to point the flow to it
664 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
665 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700666 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
667 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800668 fail(fwd, ObjectiveError.GROUPMISSING);
669 return Collections.emptySet();
670 }
671 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800672 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800673 }
674 tb.transition(ACL_TABLE);
675 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
676 .fromApp(fwd.appId())
677 .withPriority(fwd.priority())
678 .forDevice(deviceId)
679 .withSelector(filteredSelector.build())
680 .withTreatment(tb.build())
681 .forTable(forTableId);
682
683 if (fwd.permanent()) {
684 ruleBuilder.makePermanent();
685 } else {
686 ruleBuilder.makeTemporary(fwd.timeout());
687 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800688 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
689 flowRuleCollection.add(ruleBuilder.build());
690 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800691 flowRuleCollection.add(
692 defaultRoute(fwd, complementarySelector, forTableId, tb)
693 );
Flavio Castroe10fa242016-01-15 12:43:51 -0800694 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
695 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800696 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800697 }
698
Charles Chan1e492d32016-01-30 23:22:37 -0800699 @Override
700 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
701 List<FlowRule> rules = new ArrayList<>();
702
703 // Build filtered selector
704 TrafficSelector selector = fwd.selector();
705 EthCriterion ethCriterion = (EthCriterion) selector
706 .getCriterion(Criterion.Type.ETH_DST);
707 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
708 .getCriterion(Criterion.Type.VLAN_VID);
709
710 if (vlanIdCriterion == null) {
711 log.warn("Forwarding objective for bridging requires vlan. Not "
712 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
713 fail(fwd, ObjectiveError.BADPARAMS);
714 return Collections.emptySet();
715 }
716
717 TrafficSelector.Builder filteredSelectorBuilder =
718 DefaultTrafficSelector.builder();
719 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -0800720 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -0800721 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
722 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
723 fwd.id(), fwd.nextId(), deviceId);
724 } else {
725 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
726 + "in dev:{} for vlan:{}",
727 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
728 }
729 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
730 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
731
732 if (fwd.treatment() != null) {
733 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
734 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
735 }
736
737 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
738 if (fwd.nextId() != null) {
739 NextGroup next = getGroupForNextObjective(fwd.nextId());
740 if (next != null) {
741 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
742 // we only need the top level group's key to point the flow to it
743 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
744 if (group != null) {
745 treatmentBuilder.deferred().group(group.id());
746 } else {
747 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
748 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
749 fail(fwd, ObjectiveError.GROUPMISSING);
750 return Collections.emptySet();
751 }
752 }
753 }
754 treatmentBuilder.immediate().transition(ACL_TABLE);
755 TrafficTreatment filteredTreatment = treatmentBuilder.build();
756
757 // Build bridging table entries
758 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
759 flowRuleBuilder.fromApp(fwd.appId())
760 .withPriority(fwd.priority())
761 .forDevice(deviceId)
762 .withSelector(filteredSelector)
763 .withTreatment(filteredTreatment)
764 .forTable(BRIDGING_TABLE);
765 if (fwd.permanent()) {
766 flowRuleBuilder.makePermanent();
767 } else {
768 flowRuleBuilder.makeTemporary(fwd.timeout());
769 }
770 rules.add(flowRuleBuilder.build());
771 return rules;
772 }
773
Saurav Das52025962016-01-28 22:30:01 -0800774 /*
775 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
776 * ACL table. Because we pop off vlan tags in TMAC table,
777 * we need to avoid matching on vlans in the ACL table.
778 */
779 @Override
780 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
781 log.info("Processing versatile forwarding objective");
782
Saurav Das52025962016-01-28 22:30:01 -0800783 if (fwd.nextId() == null && fwd.treatment() == null) {
784 log.error("Forwarding objective {} from {} must contain "
785 + "nextId or Treatment", fwd.selector(), fwd.appId());
786 return Collections.emptySet();
787 }
788
789 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
790 fwd.selector().criteria().forEach(criterion -> {
791 if (criterion instanceof VlanIdCriterion) {
792 // avoid matching on vlans
793 return;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800794 } else if (criterion instanceof Icmpv6TypeCriterion ||
795 criterion instanceof Icmpv6CodeCriterion) {
796 /*
797 * We silenty discard these criterions, our current
798 * OFDPA platform does not support these matches on
799 * the ACL table.
800 */
801 log.warn("ICMPv6 Type and ICMPv6 Code are not supported");
Saurav Das52025962016-01-28 22:30:01 -0800802 } else {
803 sbuilder.add(criterion);
804 }
805 });
806
807 // XXX driver does not currently do type checking as per Tables 65-67 in
808 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
809 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
810 if (fwd.treatment() != null) {
811 for (Instruction ins : fwd.treatment().allInstructions()) {
812 if (ins instanceof OutputInstruction) {
813 OutputInstruction o = (OutputInstruction) ins;
814 if (o.port() == PortNumber.CONTROLLER) {
Charles Chan0f43e472017-02-14 14:00:16 -0800815 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -0800816 } else {
817 log.warn("Only allowed treatments in versatile forwarding "
818 + "objectives are punts to the controller");
819 }
Charles Chan3fe71712018-06-15 18:54:18 -0700820 } else if (ins instanceof NoActionInstruction) {
821 // No action is allowed and nothing needs to be done
Saurav Das52025962016-01-28 22:30:01 -0800822 } else {
823 log.warn("Cannot process instruction in versatile fwd {}", ins);
824 }
825 }
Charles Chan2df0e8a2017-01-09 11:45:08 -0800826 if (fwd.treatment().clearedDeferred()) {
827 ttBuilder.wipeDeferred();
828 }
Saurav Das52025962016-01-28 22:30:01 -0800829 }
830 if (fwd.nextId() != null) {
831 // overide case
832 NextGroup next = getGroupForNextObjective(fwd.nextId());
833 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
834 // we only need the top level group's key to point the flow to it
835 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
836 if (group == null) {
837 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
838 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
839 fail(fwd, ObjectiveError.GROUPMISSING);
840 return Collections.emptySet();
841 }
842 ttBuilder.deferred().group(group.id());
843 }
844
845 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
846 .fromApp(fwd.appId())
847 .withPriority(fwd.priority())
848 .forDevice(deviceId)
849 .withSelector(sbuilder.build())
850 .withTreatment(ttBuilder.build())
851 .makePermanent()
852 .forTable(ACL_TABLE);
853 return Collections.singletonList(ruleBuilder.build());
854 }
855
856 /*
857 * Cpqd emulation requires table-miss-entries in forwarding tables.
858 * Real OFDPA does not require these rules as they are put in by default.
859 *
860 * (non-Javadoc)
861 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
862 */
Saurav Das2857f382015-11-03 14:39:27 -0800863 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700864 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -0800865 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
866 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
867 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
868 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
869 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
870 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
871 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
872 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
873 initTableMiss(ACL_TABLE, -1, null);
Charles Chan4e9620d2019-11-01 16:00:39 -0700874 initPuntTable();
Charles Chan0f43e472017-02-14 14:00:16 -0800875
876 if (supportPuntGroup()) {
Charles Chan0f43e472017-02-14 14:00:16 -0800877 initPopVlanPuntGroup();
878 } else {
879 initTableMiss(PUNT_TABLE, -1,
880 DefaultTrafficTreatment.builder().popVlan().punt().build());
881 }
Saurav Das558afec2015-05-31 17:12:48 -0700882 }
883
Charles Chanf6ec1532017-02-08 16:10:40 -0800884 /**
885 * Install table-miss flow entry.
886 *
887 * If treatment exists, use it directly.
888 * Else if treatment does not exist but nextTable > 0, transit to next table.
889 * Else apply empty treatment.
890 *
891 * @param thisTable this table ID
892 * @param nextTable next table ID
893 * @param treatment traffic treatment to apply.
894 */
895 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -0700896 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -0800897 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -0700898
Charles Chanf6ec1532017-02-08 16:10:40 -0800899 if (treatment == null) {
900 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
901 if (nextTable > 0) {
902 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -0700903 }
Charles Chanf6ec1532017-02-08 16:10:40 -0800904 treatment = tBuilder.build();
905 }
Saurav Das558afec2015-05-31 17:12:48 -0700906
Charles Chanb7504392017-02-10 12:51:04 -0800907 FlowRule rule = DefaultFlowRule.builder()
908 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -0800909 .withSelector(selector)
910 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -0800911 .withPriority(LOWEST_PRIORITY)
912 .fromApp(driverId)
913 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -0800914 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -0800915 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -0800916
917 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
918 @Override
919 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800920 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800921 }
Saurav Das2857f382015-11-03 14:39:27 -0800922 @Override
923 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800924 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800925 }
926 }));
927 }
Charles Chan0f43e472017-02-14 14:00:16 -0800928
929 /**
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700930 * Install lldp/bbdp matching rules at table PUNT_TABLE
931 * that forward traffic to controller.
932 *
933 */
Charles Chan4e9620d2019-11-01 16:00:39 -0700934 private void initPuntTable() {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700935 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
936 TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build();
937
Charles Chan4e9620d2019-11-01 16:00:39 -0700938 // Add punt rule for LLDP and BDDP
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700939 TrafficSelector.Builder lldpSelector = DefaultTrafficSelector.builder();
940 lldpSelector.matchEthType(EthType.EtherType.LLDP.ethType().toShort());
941 FlowRule lldpRule = DefaultFlowRule.builder()
942 .forDevice(deviceId)
943 .withSelector(lldpSelector.build())
944 .withTreatment(treatment)
945 .withPriority(HIGHEST_PRIORITY)
946 .fromApp(driverId)
947 .makePermanent()
948 .forTable(PUNT_TABLE).build();
949 ops = ops.add(lldpRule);
950
951 TrafficSelector.Builder bbdpSelector = DefaultTrafficSelector.builder();
952 bbdpSelector.matchEthType(EthType.EtherType.BDDP.ethType().toShort());
953 FlowRule bbdpRule = DefaultFlowRule.builder()
954 .forDevice(deviceId)
955 .withSelector(bbdpSelector.build())
956 .withTreatment(treatment)
957 .withPriority(HIGHEST_PRIORITY)
958 .fromApp(driverId)
959 .makePermanent()
960 .forTable(PUNT_TABLE).build();
961 ops.add(bbdpRule);
962
963 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
964 @Override
965 public void onSuccess(FlowRuleOperations ops) {
Charles Chan4e9620d2019-11-01 16:00:39 -0700966 log.info("Initialized table {} on {}", PUNT_TABLE, deviceId);
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700967 }
968 @Override
969 public void onError(FlowRuleOperations ops) {
Charles Chan4e9620d2019-11-01 16:00:39 -0700970 log.warn("Failed to initialize table {} on {}", PUNT_TABLE, deviceId);
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700971 }
972 }));
973 }
974
975 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800976 * Builds a indirect group contains pop_vlan and punt actions.
977 * <p>
978 * Using group instead of immediate action to ensure that
979 * the copy of packet on the data plane is not affected by the pop vlan action.
980 */
981 private void initPopVlanPuntGroup() {
Yi Tsengef19de12017-04-24 11:33:05 -0700982 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -0800983 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
984 .popVlan().punt().build();
985 GroupBucket bucket =
986 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
987 GroupDescription groupDesc =
988 new DefaultGroupDescription(
989 deviceId,
990 GroupDescription.Type.INDIRECT,
991 new GroupBuckets(Collections.singletonList(bucket)),
992 groupKey,
993 POP_VLAN_PUNT_GROUP_ID,
994 driverId);
995 groupService.addGroup(groupDesc);
996
997 log.info("Initialized pop vlan punt group on {}", deviceId);
998 }
Yi Tsengef19de12017-04-24 11:33:05 -0700999
1000 /**
1001 * Generates group key for a static indirect group that pop vlan and punt to
1002 * controller.
1003 *
1004 * @return the group key of the indirect table
1005 */
1006 private GroupKey popVlanPuntGroupKey() {
1007 int hash = POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_BIT_MASK);
1008 return new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(hash));
1009 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001010
1011 private class PopVlanPuntGroupChecker implements Runnable {
1012 @Override
1013 public void run() {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -07001014 try {
1015 groupCheckerLock.lock();
1016 // this can happen outside of the lock but I think it is safer
1017 // to include it here.
1018 Group group = groupService.getGroup(deviceId, popVlanPuntGroupKey());
1019 if (group != null) {
1020 log.debug("PopVlanPuntGroupChecker: Installing {} missing rules at punt table.",
1021 flowRuleQueue.size());
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001022
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -07001023 // if we have pending flow rules install them
1024 if (flowRuleQueue.size() > 0) {
1025 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1026 // we should not care about the context here, it can only be add
1027 // since when removing the rules the group should be there already.
1028 flowRuleQueue.forEach(ops::add);
1029 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1030 @Override
1031 public void onSuccess(FlowRuleOperations ops) {
1032 log.debug("Applied {} pop vlan punt rules in device {}",
1033 ops.stages().get(0).size(), deviceId);
1034 }
1035
1036 @Override
1037 public void onError(FlowRuleOperations ops) {
1038 log.error("Failed to apply all pop vlan punt rules in dev {}", deviceId);
1039 }
1040 }));
1041 }
1042 // this signifies that the group is created and now
1043 // flow rules can be installed directly
1044 flowRuleQueue = null;
pier4d7fd092020-01-23 11:59:56 +01001045 // Schedule with an initial delay the miss table flow rule installation
1046 // the delay is to make sure the queued flows are all installed before
1047 // pushing the table miss flow rule
1048 // TODO it can be further optimized by using context and completable future
1049 groupChecker.schedule(new TableMissFlowInstaller(), 5000, TimeUnit.MILLISECONDS);
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001050 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -07001051 } finally {
1052 groupCheckerLock.unlock();
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001053 }
1054 }
1055 }
pier4d7fd092020-01-23 11:59:56 +01001056
1057 private class TableMissFlowInstaller implements Runnable {
1058 @Override
1059 public void run() {
1060 // Add table miss flow rule
1061 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1062 TrafficSelector.Builder defaultSelector = DefaultTrafficSelector.builder();
1063 TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build();
1064 FlowRule defaultRule = DefaultFlowRule.builder()
1065 .forDevice(deviceId)
1066 .withSelector(defaultSelector.build())
1067 .withTreatment(treatment)
1068 .withPriority(LOWEST_PRIORITY)
1069 .fromApp(driverId)
1070 .makePermanent()
1071 .forTable(PUNT_TABLE).build();
1072 ops.add(defaultRule);
1073 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1074 @Override
1075 public void onSuccess(FlowRuleOperations ops) {
1076 log.info("Initialized table miss flow rule {} on {}", PUNT_TABLE, deviceId);
1077 }
1078 @Override
1079 public void onError(FlowRuleOperations ops) {
1080 log.warn("Failed to initialize table miss flow rule {} on {}", PUNT_TABLE, deviceId);
1081 }
1082 }));
1083 // shutdown the group checker gracefully
1084 groupChecker.shutdown();
1085 }
1086 }
Saurav Das558afec2015-05-31 17:12:48 -07001087}