blob: 086059185326b2fed99db0c735fb6ce9d59ed62e [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) {
185 groupHandler = new CpqdOfdpa2GroupHandler();
186 groupHandler.init(deviceId, context);
Charles Chan425854b2016-04-11 15:32:12 -0700187 }
188
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700189 @Override
190 public void init(DeviceId deviceId, PipelinerContext context) {
191
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700192 if (supportPuntGroup()) {
193 // create a new executor at each init and a new empty queue
194 groupChecker = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/driver",
195 "cpqd-ofdpa-%d", log));
196 flowRuleQueue = new ConcurrentLinkedQueue<>();
197 groupCheckerLock = new ReentrantLock();
198 groupChecker.scheduleAtFixedRate(new PopVlanPuntGroupChecker(), 20, 50, TimeUnit.MILLISECONDS);
199 super.init(deviceId, context);
200 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700201 }
Saurav Das4ce45962015-11-24 23:21:05 -0800202 /*
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700203 * Cpqd emulation does not require the non OF-standard rules for
204 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800205 *
206 * (non-Javadoc)
207 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
208 */
Saurav Das558afec2015-05-31 17:12:48 -0700209 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800210 protected List<List<FlowRule>> processVlanIdFilter(PortCriterion portCriterion,
pierb2f71142019-06-10 17:10:26 +0200211 VlanIdCriterion vidCriterion,
212 VlanId assignedVlan,
213 ApplicationId applicationId,
214 boolean install) {
Charles Chan79769232016-07-05 16:34:39 -0700215 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800216 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
217 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
218 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800219 treatment.transition(TMAC_TABLE);
220
Saurav Das2857f382015-11-03 14:39:27 -0800221 if (vidCriterion.vlanId() == VlanId.NONE) {
222 // untagged packets are assigned vlans
223 treatment.pushVlan().setVlanId(assignedVlan);
Pier3cc7e662018-03-07 11:42:50 +0100224 } else if (!vidCriterion.vlanId().equals(assignedVlan)) {
225 // Rewrite with assigned vlans
226 treatment.setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800227 }
Saurav Das2857f382015-11-03 14:39:27 -0800228
229 // ofdpa cannot match on ALL portnumber, so we need to use separate
230 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800231 List<PortNumber> portnums = new ArrayList<>();
Ray Milkey94542b02018-05-10 12:42:51 -0700232 if (portCriterion != null) {
233 if (portCriterion.port() == PortNumber.ALL) {
234 for (Port port : deviceService.getPorts(deviceId)) {
235 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
236 portnums.add(port.number());
237 }
Saurav Das2857f382015-11-03 14:39:27 -0800238 }
Ray Milkey94542b02018-05-10 12:42:51 -0700239 } else {
240 portnums.add(portCriterion.port());
Saurav Das2857f382015-11-03 14:39:27 -0800241 }
Saurav Das2857f382015-11-03 14:39:27 -0800242 }
Saurav Das4f980082015-11-05 13:39:15 -0800243
Saurav Das2857f382015-11-03 14:39:27 -0800244 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800245 // NOTE: Emulating OFDPA behavior by popping off internal assigned
246 // VLAN before sending to controller
247 if (supportPuntGroup() && vidCriterion.vlanId() == VlanId.NONE) {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700248 try {
249 groupCheckerLock.lock();
250 if (flowRuleQueue == null) {
251 // this means that the group has been created
252 // and that groupChecker has destroyed the queue
253 log.debug("Installing punt table rule for untagged port {} and vlan {}.",
254 pnum, assignedVlan);
255 rules.add(buildPuntTableRule(pnum, assignedVlan));
256 } else {
257 // The VLAN punt group may be held back due to device initial audit.
258 // In that case, we queue all punt table flow until the group has been created.
259 log.debug("popVlanPuntGroup not found in dev:{}, queueing this flow rule.", deviceId);
260 flowRuleQueue.add(buildPuntTableRule(pnum, assignedVlan));
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700261 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700262 } finally {
263 groupCheckerLock.unlock();
Charles Chan0f43e472017-02-14 14:00:16 -0800264 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700265 } else if (vidCriterion.vlanId() != VlanId.NONE) {
266 // for tagged ports just forward to the controller
267 log.debug("Installing punt rule for tagged port {} and vlan {}.", pnum, vidCriterion.vlanId());
268 rules.add(buildPuntTableRuleTagged(pnum, vidCriterion.vlanId()));
Charles Chan0f43e472017-02-14 14:00:16 -0800269 }
270
Saurav Das4f980082015-11-05 13:39:15 -0800271 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800272 selector.matchInPort(pnum);
273 FlowRule rule = DefaultFlowRule.builder()
274 .forDevice(deviceId)
275 .withSelector(selector.build())
276 .withTreatment(treatment.build())
277 .withPriority(DEFAULT_PRIORITY)
278 .fromApp(applicationId)
279 .makePermanent()
280 .forTable(VLAN_TABLE).build();
281 rules.add(rule);
282 }
Charles Chanf57a8252016-06-29 19:12:37 -0700283
Charles Chan206506b2018-03-02 16:43:28 -0800284 return ImmutableList.of(rules);
Saurav Das2857f382015-11-03 14:39:27 -0800285 }
286
Pier Ventree0ae7a32016-11-23 09:57:42 -0800287 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800288 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
289 * a group that pop vlan and punt.
290 *
291 * @param portNumber port number
292 * @param assignedVlan internally assigned vlan id
293 * @return punt table flow rule
294 */
295 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
296 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
297 .matchInPort(portNumber)
298 .matchVlanId(assignedVlan);
299 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
Yi Tsengfa394de2017-02-01 11:26:40 -0800300 .group(new GroupId(POP_VLAN_PUNT_GROUP_ID));
Charles Chan0f43e472017-02-14 14:00:16 -0800301
302 return DefaultFlowRule.builder()
303 .forDevice(deviceId)
304 .withSelector(sbuilder.build())
305 .withTreatment(tbuilder.build())
306 .withPriority(PacketPriority.CONTROL.priorityValue())
307 .fromApp(driverId)
308 .makePermanent()
309 .forTable(PUNT_TABLE).build();
310 }
311
312 /**
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700313 * Creates punt table entry that matches IN_PORT and VLAN_VID and forwards
314 * packet to controller tagged.
315 *
316 * @param portNumber port number
317 * @param packetVlan vlan tag of the packet
318 * @return punt table flow rule
319 */
320 private FlowRule buildPuntTableRuleTagged(PortNumber portNumber, VlanId packetVlan) {
321 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
322 .matchInPort(portNumber)
323 .matchVlanId(packetVlan);
324 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder().punt();
325
326 return DefaultFlowRule.builder()
327 .forDevice(deviceId)
328 .withSelector(sbuilder.build())
329 .withTreatment(tbuilder.build())
330 .withPriority(PacketPriority.CONTROL.priorityValue())
331 .fromApp(driverId)
332 .makePermanent()
333 .forTable(PUNT_TABLE).build();
334 }
335
336 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800337 * Builds a punt to the controller rule for the arp protocol.
Charles Chan0f43e472017-02-14 14:00:16 -0800338 * <p>
339 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
340 * pop VLAN before sending to controller disregarding whether
341 * it's an internally assigned VLAN or a natural VLAN.
342 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800343 *
344 * @param assignedVlan the internal assigned vlan id
345 * @param applicationId the application id
346 * @return the punt flow rule for the arp
347 */
348 private FlowRule buildArpPunt(VlanId assignedVlan, ApplicationId applicationId) {
349 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
350 .matchEthType(Ethernet.TYPE_ARP)
351 .matchVlanId(assignedVlan);
352 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
353 .popVlan()
354 .punt();
355
356 return DefaultFlowRule.builder()
357 .forDevice(deviceId)
358 .withSelector(sbuilder.build())
359 .withTreatment(tbuilder.build())
360 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
361 .fromApp(applicationId)
362 .makePermanent()
363 .forTable(ACL_TABLE).build();
364 }
365
366 /**
367 * Builds a punt to the controller rule for the icmp v6 messages.
Charles Chan0f43e472017-02-14 14:00:16 -0800368 * <p>
369 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
370 * pop VLAN before sending to controller disregarding whether
371 * it's an internally assigned VLAN or a natural VLAN.
372 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800373 *
374 * @param assignedVlan the internal assigned vlan id
375 * @param applicationId the application id
376 * @return the punt flow rule for the icmp v6 messages
377 */
378 private FlowRule buildIcmpV6Punt(VlanId assignedVlan, ApplicationId applicationId) {
379 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
380 .matchVlanId(assignedVlan)
381 .matchEthType(Ethernet.TYPE_IPV6)
382 .matchIPProtocol(PROTOCOL_ICMP6);
383 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
384 .popVlan()
385 .punt();
386
387 return DefaultFlowRule.builder()
388 .forDevice(deviceId)
389 .withSelector(sbuilder.build())
390 .withTreatment(tbuilder.build())
391 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
392 .fromApp(applicationId)
393 .makePermanent()
394 .forTable(ACL_TABLE).build();
395 }
396
Saurav Das4ce45962015-11-24 23:21:05 -0800397 /*
398 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
399 * Workaround requires popping off the VLAN tags in the TMAC table.
400 *
401 * (non-Javadoc)
402 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
403 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800404 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800405 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das4ce45962015-11-24 23:21:05 -0800406 EthCriterion ethCriterion,
407 VlanIdCriterion vidCriterion,
408 VlanId assignedVlan,
Charles Chand57552d2018-03-02 15:41:41 -0800409 MacAddress unicastMac,
Saurav Das4ce45962015-11-24 23:21:05 -0800410 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800411 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
412 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
413 return processEthDstOnlyFilter(ethCriterion, applicationId);
414 }
415
Charles Chan5b9df8d2016-03-28 22:21:40 -0700416 // Multicast MAC
417 if (ethCriterion.mask() != null) {
Charles Chand57552d2018-03-02 15:41:41 -0800418 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700419 }
420
Saurav Das4ce45962015-11-24 23:21:05 -0800421 //handling untagged packets via assigned VLAN
422 if (vidCriterion.vlanId() == VlanId.NONE) {
423 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
424 }
425 // ofdpa cannot match on ALL portnumber, so we need to use separate
426 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800427 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800428 if (portCriterion != null) {
429 if (portCriterion.port() == PortNumber.ALL) {
430 for (Port port : deviceService.getPorts(deviceId)) {
431 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
432 portnums.add(port.number());
433 }
Saurav Das4ce45962015-11-24 23:21:05 -0800434 }
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800435 } else {
436 portnums.add(portCriterion.port());
Saurav Das4ce45962015-11-24 23:21:05 -0800437 }
Saurav Das4ce45962015-11-24 23:21:05 -0800438 }
439
Charles Chan93090352018-03-02 13:26:22 -0800440 List<FlowRule> rules = new ArrayList<>();
Saurav Das4ce45962015-11-24 23:21:05 -0800441 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800442 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800443 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
444 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
445 selector.matchInPort(pnum);
446 selector.matchVlanId(vidCriterion.vlanId());
447 selector.matchEthType(Ethernet.TYPE_IPV4);
448 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800449 if (!supportTaggedMpls()) {
450 treatment.popVlan();
451 }
Saurav Das4ce45962015-11-24 23:21:05 -0800452 treatment.transition(UNICAST_ROUTING_TABLE);
453 FlowRule rule = DefaultFlowRule.builder()
454 .forDevice(deviceId)
455 .withSelector(selector.build())
456 .withTreatment(treatment.build())
457 .withPriority(DEFAULT_PRIORITY)
458 .fromApp(applicationId)
459 .makePermanent()
460 .forTable(TMAC_TABLE).build();
461 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800462
463 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800464 selector = DefaultTrafficSelector.builder();
465 treatment = DefaultTrafficTreatment.builder();
466 selector.matchInPort(pnum);
467 selector.matchVlanId(vidCriterion.vlanId());
468 selector.matchEthType(Ethernet.MPLS_UNICAST);
469 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800470 if (!supportTaggedMpls()) {
471 treatment.popVlan();
472 }
Saurav Das4ce45962015-11-24 23:21:05 -0800473 treatment.transition(MPLS_TABLE_0);
474 rule = DefaultFlowRule.builder()
475 .forDevice(deviceId)
476 .withSelector(selector.build())
477 .withTreatment(treatment.build())
478 .withPriority(DEFAULT_PRIORITY)
479 .fromApp(applicationId)
480 .makePermanent()
481 .forTable(TMAC_TABLE).build();
482 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800483
484 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800485 selector = DefaultTrafficSelector.builder();
486 treatment = DefaultTrafficTreatment.builder();
487 selector.matchInPort(pnum);
488 selector.matchVlanId(vidCriterion.vlanId());
489 selector.matchEthType(Ethernet.TYPE_IPV6);
490 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800491 if (!supportTaggedMpls()) {
492 treatment.popVlan();
493 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800494 treatment.transition(UNICAST_ROUTING_TABLE);
495 rule = DefaultFlowRule.builder()
496 .forDevice(deviceId)
497 .withSelector(selector.build())
498 .withTreatment(treatment.build())
499 .withPriority(DEFAULT_PRIORITY)
500 .fromApp(applicationId)
501 .makePermanent()
502 .forTable(TMAC_TABLE).build();
503 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800504 }
Charles Chan206506b2018-03-02 16:43:28 -0800505 return ImmutableList.of(rules);
Saurav Das4ce45962015-11-24 23:21:05 -0800506 }
507
Charles Chan5270ed02016-01-30 23:22:37 -0800508 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800509 protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700510 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800511 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
512 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
513 selector.matchEthType(Ethernet.TYPE_IPV4);
514 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800515 if (!supportTaggedMpls()) {
516 treatment.popVlan();
517 }
Charles Chan5270ed02016-01-30 23:22:37 -0800518 treatment.transition(UNICAST_ROUTING_TABLE);
519 FlowRule rule = DefaultFlowRule.builder()
520 .forDevice(deviceId)
521 .withSelector(selector.build())
522 .withTreatment(treatment.build())
523 .withPriority(DEFAULT_PRIORITY)
524 .fromApp(applicationId)
525 .makePermanent()
526 .forTable(TMAC_TABLE).build();
Charles Chan206506b2018-03-02 16:43:28 -0800527 return ImmutableList.of(ImmutableList.of(rule));
Charles Chan5270ed02016-01-30 23:22:37 -0800528 }
529
Saurav Das4ce45962015-11-24 23:21:05 -0800530 /*
531 * Cpqd emulation allows MPLS ecmp.
532 *
533 * (non-Javadoc)
534 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
535 */
536 @Override
537 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800538 TrafficSelector selector = fwd.selector();
539 EthTypeCriterion ethType =
540 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
541 if ((ethType == null) ||
542 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800543 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
544 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800545 log.warn("processSpecific: Unsupported forwarding objective criteria"
546 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800547 fail(fwd, ObjectiveError.UNSUPPORTED);
548 return Collections.emptySet();
549 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800550 boolean defaultRule = false;
Charles Chan93090352018-03-02 13:26:22 -0800551 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800552 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800553 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
554
Saurav Das8a0732e2015-11-20 15:27:53 -0800555 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800556 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700557 if (ipv4Dst.isMulticast()) {
558 if (ipv4Dst.prefixLength() != 32) {
559 log.warn("Multicast specific forwarding objective can only be /32");
560 fail(fwd, ObjectiveError.BADPARAMS);
561 return ImmutableSet.of();
562 }
563 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
564 if (assignedVlan == null) {
565 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
566 fail(fwd, ObjectiveError.BADPARAMS);
567 return ImmutableSet.of();
568 }
569 filteredSelector.matchVlanId(assignedVlan);
570 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
571 forTableId = MULTICAST_ROUTING_TABLE;
572 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
573 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800574 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700575 if (ipv4Dst.prefixLength() == 0) {
576 // The entire IPV4_DST field is wildcarded intentionally
577 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700578 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700579 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700580 }
581 forTableId = UNICAST_ROUTING_TABLE;
582 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
583 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800584 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800585 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
Julia Ferguson65428c32017-08-10 18:15:24 +0000586 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
587 if (ipv6Dst.isMulticast()) {
588 if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
589 log.debug("Multicast specific IPv6 forwarding objective can only be /128");
590 fail(fwd, ObjectiveError.BADPARAMS);
591 return ImmutableSet.of();
592 }
593 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
594 if (assignedVlan == null) {
595 log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
596 fail(fwd, ObjectiveError.BADPARAMS);
597 return ImmutableSet.of();
598 }
599 filteredSelector.matchVlanId(assignedVlan);
600 filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
601 forTableId = MULTICAST_ROUTING_TABLE;
602 log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
603 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
604 } else {
605 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
606 return Collections.emptyList();
607 }
608 forTableId = UNICAST_ROUTING_TABLE;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800609 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800610 } else {
611 filteredSelector
612 .matchEthType(Ethernet.MPLS_UNICAST)
613 .matchMplsLabel(((MplsCriterion)
614 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
615 MplsBosCriterion bos = (MplsBosCriterion) selector
616 .getCriterion(Criterion.Type.MPLS_BOS);
617 if (bos != null) {
618 filteredSelector.matchMplsBos(bos.mplsBos());
619 }
620 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800621 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
622 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800623 }
624
625 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
626 if (fwd.treatment() != null) {
627 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan40132b32017-01-22 00:19:37 -0800628 if (!supportCopyTtl() && i instanceof L3ModificationInstruction) {
629 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
630 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
631 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
632 continue;
633 }
634 }
Charles Chan7d10b162015-12-07 18:54:45 -0800635 /*
636 * NOTE: OF-DPA does not support immediate instruction in
637 * L3 unicast and MPLS table.
638 */
639 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800640 }
641 }
642
643 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800644 NextGroup next = getGroupForNextObjective(fwd.nextId());
645 if (next != null) {
646 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
647 // we only need the top level group's key to point the flow to it
648 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
649 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700650 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
651 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800652 fail(fwd, ObjectiveError.GROUPMISSING);
653 return Collections.emptySet();
654 }
655 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800656 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800657 }
658 tb.transition(ACL_TABLE);
659 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
660 .fromApp(fwd.appId())
661 .withPriority(fwd.priority())
662 .forDevice(deviceId)
663 .withSelector(filteredSelector.build())
664 .withTreatment(tb.build())
665 .forTable(forTableId);
666
667 if (fwd.permanent()) {
668 ruleBuilder.makePermanent();
669 } else {
670 ruleBuilder.makeTemporary(fwd.timeout());
671 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800672 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
673 flowRuleCollection.add(ruleBuilder.build());
674 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800675 flowRuleCollection.add(
676 defaultRoute(fwd, complementarySelector, forTableId, tb)
677 );
Flavio Castroe10fa242016-01-15 12:43:51 -0800678 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
679 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800680 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800681 }
682
Charles Chan1e492d32016-01-30 23:22:37 -0800683 @Override
684 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
685 List<FlowRule> rules = new ArrayList<>();
686
687 // Build filtered selector
688 TrafficSelector selector = fwd.selector();
689 EthCriterion ethCriterion = (EthCriterion) selector
690 .getCriterion(Criterion.Type.ETH_DST);
691 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
692 .getCriterion(Criterion.Type.VLAN_VID);
693
694 if (vlanIdCriterion == null) {
695 log.warn("Forwarding objective for bridging requires vlan. Not "
696 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
697 fail(fwd, ObjectiveError.BADPARAMS);
698 return Collections.emptySet();
699 }
700
701 TrafficSelector.Builder filteredSelectorBuilder =
702 DefaultTrafficSelector.builder();
703 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -0800704 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -0800705 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
706 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
707 fwd.id(), fwd.nextId(), deviceId);
708 } else {
709 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
710 + "in dev:{} for vlan:{}",
711 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
712 }
713 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
714 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
715
716 if (fwd.treatment() != null) {
717 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
718 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
719 }
720
721 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
722 if (fwd.nextId() != null) {
723 NextGroup next = getGroupForNextObjective(fwd.nextId());
724 if (next != null) {
725 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
726 // we only need the top level group's key to point the flow to it
727 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
728 if (group != null) {
729 treatmentBuilder.deferred().group(group.id());
730 } else {
731 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
732 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
733 fail(fwd, ObjectiveError.GROUPMISSING);
734 return Collections.emptySet();
735 }
736 }
737 }
738 treatmentBuilder.immediate().transition(ACL_TABLE);
739 TrafficTreatment filteredTreatment = treatmentBuilder.build();
740
741 // Build bridging table entries
742 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
743 flowRuleBuilder.fromApp(fwd.appId())
744 .withPriority(fwd.priority())
745 .forDevice(deviceId)
746 .withSelector(filteredSelector)
747 .withTreatment(filteredTreatment)
748 .forTable(BRIDGING_TABLE);
749 if (fwd.permanent()) {
750 flowRuleBuilder.makePermanent();
751 } else {
752 flowRuleBuilder.makeTemporary(fwd.timeout());
753 }
754 rules.add(flowRuleBuilder.build());
755 return rules;
756 }
757
Saurav Das52025962016-01-28 22:30:01 -0800758 /*
759 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
760 * ACL table. Because we pop off vlan tags in TMAC table,
761 * we need to avoid matching on vlans in the ACL table.
762 */
763 @Override
764 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
765 log.info("Processing versatile forwarding objective");
766
Saurav Das52025962016-01-28 22:30:01 -0800767 if (fwd.nextId() == null && fwd.treatment() == null) {
768 log.error("Forwarding objective {} from {} must contain "
769 + "nextId or Treatment", fwd.selector(), fwd.appId());
770 return Collections.emptySet();
771 }
772
773 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
774 fwd.selector().criteria().forEach(criterion -> {
775 if (criterion instanceof VlanIdCriterion) {
776 // avoid matching on vlans
777 return;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800778 } else if (criterion instanceof Icmpv6TypeCriterion ||
779 criterion instanceof Icmpv6CodeCriterion) {
780 /*
781 * We silenty discard these criterions, our current
782 * OFDPA platform does not support these matches on
783 * the ACL table.
784 */
785 log.warn("ICMPv6 Type and ICMPv6 Code are not supported");
Saurav Das52025962016-01-28 22:30:01 -0800786 } else {
787 sbuilder.add(criterion);
788 }
789 });
790
791 // XXX driver does not currently do type checking as per Tables 65-67 in
792 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
793 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
794 if (fwd.treatment() != null) {
795 for (Instruction ins : fwd.treatment().allInstructions()) {
796 if (ins instanceof OutputInstruction) {
797 OutputInstruction o = (OutputInstruction) ins;
798 if (o.port() == PortNumber.CONTROLLER) {
Charles Chan0f43e472017-02-14 14:00:16 -0800799 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -0800800 } else {
801 log.warn("Only allowed treatments in versatile forwarding "
802 + "objectives are punts to the controller");
803 }
Charles Chan3fe71712018-06-15 18:54:18 -0700804 } else if (ins instanceof NoActionInstruction) {
805 // No action is allowed and nothing needs to be done
Saurav Das52025962016-01-28 22:30:01 -0800806 } else {
807 log.warn("Cannot process instruction in versatile fwd {}", ins);
808 }
809 }
Charles Chan2df0e8a2017-01-09 11:45:08 -0800810 if (fwd.treatment().clearedDeferred()) {
811 ttBuilder.wipeDeferred();
812 }
Saurav Das52025962016-01-28 22:30:01 -0800813 }
814 if (fwd.nextId() != null) {
815 // overide case
816 NextGroup next = getGroupForNextObjective(fwd.nextId());
817 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
818 // we only need the top level group's key to point the flow to it
819 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
820 if (group == null) {
821 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
822 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
823 fail(fwd, ObjectiveError.GROUPMISSING);
824 return Collections.emptySet();
825 }
826 ttBuilder.deferred().group(group.id());
827 }
828
829 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
830 .fromApp(fwd.appId())
831 .withPriority(fwd.priority())
832 .forDevice(deviceId)
833 .withSelector(sbuilder.build())
834 .withTreatment(ttBuilder.build())
835 .makePermanent()
836 .forTable(ACL_TABLE);
837 return Collections.singletonList(ruleBuilder.build());
838 }
839
840 /*
841 * Cpqd emulation requires table-miss-entries in forwarding tables.
842 * Real OFDPA does not require these rules as they are put in by default.
843 *
844 * (non-Javadoc)
845 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
846 */
Saurav Das2857f382015-11-03 14:39:27 -0800847 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700848 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -0800849 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
850 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
851 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
852 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
853 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
854 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
855 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
856 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
857 initTableMiss(ACL_TABLE, -1, null);
Charles Chan4e9620d2019-11-01 16:00:39 -0700858 initPuntTable();
Charles Chan0f43e472017-02-14 14:00:16 -0800859
860 if (supportPuntGroup()) {
Charles Chan0f43e472017-02-14 14:00:16 -0800861 initPopVlanPuntGroup();
862 } else {
863 initTableMiss(PUNT_TABLE, -1,
864 DefaultTrafficTreatment.builder().popVlan().punt().build());
865 }
Saurav Das558afec2015-05-31 17:12:48 -0700866 }
867
Charles Chanf6ec1532017-02-08 16:10:40 -0800868 /**
869 * Install table-miss flow entry.
870 *
871 * If treatment exists, use it directly.
872 * Else if treatment does not exist but nextTable > 0, transit to next table.
873 * Else apply empty treatment.
874 *
875 * @param thisTable this table ID
876 * @param nextTable next table ID
877 * @param treatment traffic treatment to apply.
878 */
879 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -0700880 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -0800881 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -0700882
Charles Chanf6ec1532017-02-08 16:10:40 -0800883 if (treatment == null) {
884 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
885 if (nextTable > 0) {
886 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -0700887 }
Charles Chanf6ec1532017-02-08 16:10:40 -0800888 treatment = tBuilder.build();
889 }
Saurav Das558afec2015-05-31 17:12:48 -0700890
Charles Chanb7504392017-02-10 12:51:04 -0800891 FlowRule rule = DefaultFlowRule.builder()
892 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -0800893 .withSelector(selector)
894 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -0800895 .withPriority(LOWEST_PRIORITY)
896 .fromApp(driverId)
897 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -0800898 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -0800899 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -0800900
901 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
902 @Override
903 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800904 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800905 }
Saurav Das2857f382015-11-03 14:39:27 -0800906 @Override
907 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800908 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800909 }
910 }));
911 }
Charles Chan0f43e472017-02-14 14:00:16 -0800912
913 /**
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700914 * Install lldp/bbdp matching rules at table PUNT_TABLE
915 * that forward traffic to controller.
916 *
917 */
Charles Chan4e9620d2019-11-01 16:00:39 -0700918 private void initPuntTable() {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700919 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
920 TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build();
921
Charles Chan4e9620d2019-11-01 16:00:39 -0700922 // Add punt rule for LLDP and BDDP
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700923 TrafficSelector.Builder lldpSelector = DefaultTrafficSelector.builder();
924 lldpSelector.matchEthType(EthType.EtherType.LLDP.ethType().toShort());
925 FlowRule lldpRule = DefaultFlowRule.builder()
926 .forDevice(deviceId)
927 .withSelector(lldpSelector.build())
928 .withTreatment(treatment)
929 .withPriority(HIGHEST_PRIORITY)
930 .fromApp(driverId)
931 .makePermanent()
932 .forTable(PUNT_TABLE).build();
933 ops = ops.add(lldpRule);
934
935 TrafficSelector.Builder bbdpSelector = DefaultTrafficSelector.builder();
936 bbdpSelector.matchEthType(EthType.EtherType.BDDP.ethType().toShort());
937 FlowRule bbdpRule = DefaultFlowRule.builder()
938 .forDevice(deviceId)
939 .withSelector(bbdpSelector.build())
940 .withTreatment(treatment)
941 .withPriority(HIGHEST_PRIORITY)
942 .fromApp(driverId)
943 .makePermanent()
944 .forTable(PUNT_TABLE).build();
945 ops.add(bbdpRule);
946
Charles Chan4e9620d2019-11-01 16:00:39 -0700947 // Add table miss flow rule
948 TrafficSelector.Builder defaultSelector = DefaultTrafficSelector.builder();
949 FlowRule defaultRule = DefaultFlowRule.builder()
950 .forDevice(deviceId)
951 .withSelector(defaultSelector.build())
952 .withTreatment(treatment)
953 .withPriority(LOWEST_PRIORITY)
954 .fromApp(driverId)
955 .makePermanent()
956 .forTable(PUNT_TABLE).build();
957 ops.add(defaultRule);
958
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700959 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
960 @Override
961 public void onSuccess(FlowRuleOperations ops) {
Charles Chan4e9620d2019-11-01 16:00:39 -0700962 log.info("Initialized table {} on {}", PUNT_TABLE, deviceId);
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700963 }
964 @Override
965 public void onError(FlowRuleOperations ops) {
Charles Chan4e9620d2019-11-01 16:00:39 -0700966 log.warn("Failed to initialize table {} on {}", PUNT_TABLE, deviceId);
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700967 }
968 }));
969 }
970
971 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800972 * Builds a indirect group contains pop_vlan and punt actions.
973 * <p>
974 * Using group instead of immediate action to ensure that
975 * the copy of packet on the data plane is not affected by the pop vlan action.
976 */
977 private void initPopVlanPuntGroup() {
Yi Tsengef19de12017-04-24 11:33:05 -0700978 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -0800979 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
980 .popVlan().punt().build();
981 GroupBucket bucket =
982 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
983 GroupDescription groupDesc =
984 new DefaultGroupDescription(
985 deviceId,
986 GroupDescription.Type.INDIRECT,
987 new GroupBuckets(Collections.singletonList(bucket)),
988 groupKey,
989 POP_VLAN_PUNT_GROUP_ID,
990 driverId);
991 groupService.addGroup(groupDesc);
992
993 log.info("Initialized pop vlan punt group on {}", deviceId);
994 }
Yi Tsengef19de12017-04-24 11:33:05 -0700995
996 /**
997 * Generates group key for a static indirect group that pop vlan and punt to
998 * controller.
999 *
1000 * @return the group key of the indirect table
1001 */
1002 private GroupKey popVlanPuntGroupKey() {
1003 int hash = POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_BIT_MASK);
1004 return new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(hash));
1005 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001006
1007 private class PopVlanPuntGroupChecker implements Runnable {
1008 @Override
1009 public void run() {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -07001010 try {
1011 groupCheckerLock.lock();
1012 // this can happen outside of the lock but I think it is safer
1013 // to include it here.
1014 Group group = groupService.getGroup(deviceId, popVlanPuntGroupKey());
1015 if (group != null) {
1016 log.debug("PopVlanPuntGroupChecker: Installing {} missing rules at punt table.",
1017 flowRuleQueue.size());
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001018
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -07001019 // if we have pending flow rules install them
1020 if (flowRuleQueue.size() > 0) {
1021 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1022 // we should not care about the context here, it can only be add
1023 // since when removing the rules the group should be there already.
1024 flowRuleQueue.forEach(ops::add);
1025 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1026 @Override
1027 public void onSuccess(FlowRuleOperations ops) {
1028 log.debug("Applied {} pop vlan punt rules in device {}",
1029 ops.stages().get(0).size(), deviceId);
1030 }
1031
1032 @Override
1033 public void onError(FlowRuleOperations ops) {
1034 log.error("Failed to apply all pop vlan punt rules in dev {}", deviceId);
1035 }
1036 }));
1037 }
1038 // this signifies that the group is created and now
1039 // flow rules can be installed directly
1040 flowRuleQueue = null;
1041 // shutdown the group checker gracefully
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001042 groupChecker.shutdown();
1043 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -07001044 } finally {
1045 groupCheckerLock.unlock();
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001046 }
1047 }
1048 }
Saurav Das558afec2015-05-31 17:12:48 -07001049}