blob: 85ce51b2fb303c5f4c6f8337a4329e8c0ac6d2b6 [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) {
piera3b186e2020-02-28 09:24:11 +0100191 if (!ready.getAndSet(true)) {
192 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 Pantelopoulosc78c1f52018-06-04 15:10:35 -0700201 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700202 }
Saurav Das4ce45962015-11-24 23:21:05 -0800203 /*
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700204 * Cpqd emulation does not require the non OF-standard rules for
205 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800206 *
207 * (non-Javadoc)
208 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
209 */
Saurav Das558afec2015-05-31 17:12:48 -0700210 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800211 protected List<List<FlowRule>> processVlanIdFilter(PortCriterion portCriterion,
pierb2f71142019-06-10 17:10:26 +0200212 VlanIdCriterion vidCriterion,
213 VlanId assignedVlan,
214 ApplicationId applicationId,
215 boolean install) {
Charles Chan79769232016-07-05 16:34:39 -0700216 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800217 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
218 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
219 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800220 treatment.transition(TMAC_TABLE);
221
Saurav Das2857f382015-11-03 14:39:27 -0800222 if (vidCriterion.vlanId() == VlanId.NONE) {
223 // untagged packets are assigned vlans
224 treatment.pushVlan().setVlanId(assignedVlan);
Pier3cc7e662018-03-07 11:42:50 +0100225 } else if (!vidCriterion.vlanId().equals(assignedVlan)) {
226 // Rewrite with assigned vlans
227 treatment.setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800228 }
Saurav Das2857f382015-11-03 14:39:27 -0800229
230 // ofdpa cannot match on ALL portnumber, so we need to use separate
231 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800232 List<PortNumber> portnums = new ArrayList<>();
Ray Milkey94542b02018-05-10 12:42:51 -0700233 if (portCriterion != null) {
234 if (portCriterion.port() == PortNumber.ALL) {
235 for (Port port : deviceService.getPorts(deviceId)) {
236 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
237 portnums.add(port.number());
238 }
Saurav Das2857f382015-11-03 14:39:27 -0800239 }
Ray Milkey94542b02018-05-10 12:42:51 -0700240 } else {
241 portnums.add(portCriterion.port());
Saurav Das2857f382015-11-03 14:39:27 -0800242 }
Saurav Das2857f382015-11-03 14:39:27 -0800243 }
Saurav Das4f980082015-11-05 13:39:15 -0800244
Saurav Das2857f382015-11-03 14:39:27 -0800245 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800246 // NOTE: Emulating OFDPA behavior by popping off internal assigned
247 // VLAN before sending to controller
248 if (supportPuntGroup() && vidCriterion.vlanId() == VlanId.NONE) {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700249 try {
250 groupCheckerLock.lock();
251 if (flowRuleQueue == null) {
252 // this means that the group has been created
253 // and that groupChecker has destroyed the queue
254 log.debug("Installing punt table rule for untagged port {} and vlan {}.",
255 pnum, assignedVlan);
256 rules.add(buildPuntTableRule(pnum, assignedVlan));
257 } else {
258 // The VLAN punt group may be held back due to device initial audit.
259 // In that case, we queue all punt table flow until the group has been created.
260 log.debug("popVlanPuntGroup not found in dev:{}, queueing this flow rule.", deviceId);
261 flowRuleQueue.add(buildPuntTableRule(pnum, assignedVlan));
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700262 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700263 } finally {
264 groupCheckerLock.unlock();
Charles Chan0f43e472017-02-14 14:00:16 -0800265 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700266 } else if (vidCriterion.vlanId() != VlanId.NONE) {
267 // for tagged ports just forward to the controller
268 log.debug("Installing punt rule for tagged port {} and vlan {}.", pnum, vidCriterion.vlanId());
269 rules.add(buildPuntTableRuleTagged(pnum, vidCriterion.vlanId()));
Charles Chan0f43e472017-02-14 14:00:16 -0800270 }
271
Saurav Das4f980082015-11-05 13:39:15 -0800272 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800273 selector.matchInPort(pnum);
274 FlowRule rule = DefaultFlowRule.builder()
275 .forDevice(deviceId)
276 .withSelector(selector.build())
277 .withTreatment(treatment.build())
278 .withPriority(DEFAULT_PRIORITY)
279 .fromApp(applicationId)
280 .makePermanent()
281 .forTable(VLAN_TABLE).build();
282 rules.add(rule);
283 }
Charles Chanf57a8252016-06-29 19:12:37 -0700284
Charles Chan206506b2018-03-02 16:43:28 -0800285 return ImmutableList.of(rules);
Saurav Das2857f382015-11-03 14:39:27 -0800286 }
287
Pier Ventree0ae7a32016-11-23 09:57:42 -0800288 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800289 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
290 * a group that pop vlan and punt.
291 *
292 * @param portNumber port number
293 * @param assignedVlan internally assigned vlan id
294 * @return punt table flow rule
295 */
296 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
297 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
298 .matchInPort(portNumber)
299 .matchVlanId(assignedVlan);
300 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
Yi Tsengfa394de2017-02-01 11:26:40 -0800301 .group(new GroupId(POP_VLAN_PUNT_GROUP_ID));
Charles Chan0f43e472017-02-14 14:00:16 -0800302
303 return DefaultFlowRule.builder()
304 .forDevice(deviceId)
305 .withSelector(sbuilder.build())
306 .withTreatment(tbuilder.build())
307 .withPriority(PacketPriority.CONTROL.priorityValue())
308 .fromApp(driverId)
309 .makePermanent()
310 .forTable(PUNT_TABLE).build();
311 }
312
313 /**
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700314 * Creates punt table entry that matches IN_PORT and VLAN_VID and forwards
315 * packet to controller tagged.
316 *
317 * @param portNumber port number
318 * @param packetVlan vlan tag of the packet
319 * @return punt table flow rule
320 */
321 private FlowRule buildPuntTableRuleTagged(PortNumber portNumber, VlanId packetVlan) {
322 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
323 .matchInPort(portNumber)
324 .matchVlanId(packetVlan);
325 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder().punt();
326
327 return DefaultFlowRule.builder()
328 .forDevice(deviceId)
329 .withSelector(sbuilder.build())
330 .withTreatment(tbuilder.build())
331 .withPriority(PacketPriority.CONTROL.priorityValue())
332 .fromApp(driverId)
333 .makePermanent()
334 .forTable(PUNT_TABLE).build();
335 }
336
337 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800338 * Builds a punt to the controller rule for the arp protocol.
Charles Chan0f43e472017-02-14 14:00:16 -0800339 * <p>
340 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
341 * pop VLAN before sending to controller disregarding whether
342 * it's an internally assigned VLAN or a natural VLAN.
343 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800344 *
345 * @param assignedVlan the internal assigned vlan id
346 * @param applicationId the application id
347 * @return the punt flow rule for the arp
348 */
349 private FlowRule buildArpPunt(VlanId assignedVlan, ApplicationId applicationId) {
350 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
351 .matchEthType(Ethernet.TYPE_ARP)
352 .matchVlanId(assignedVlan);
353 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
354 .popVlan()
355 .punt();
356
357 return DefaultFlowRule.builder()
358 .forDevice(deviceId)
359 .withSelector(sbuilder.build())
360 .withTreatment(tbuilder.build())
361 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
362 .fromApp(applicationId)
363 .makePermanent()
364 .forTable(ACL_TABLE).build();
365 }
366
367 /**
368 * Builds a punt to the controller rule for the icmp v6 messages.
Charles Chan0f43e472017-02-14 14:00:16 -0800369 * <p>
370 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
371 * pop VLAN before sending to controller disregarding whether
372 * it's an internally assigned VLAN or a natural VLAN.
373 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800374 *
375 * @param assignedVlan the internal assigned vlan id
376 * @param applicationId the application id
377 * @return the punt flow rule for the icmp v6 messages
378 */
379 private FlowRule buildIcmpV6Punt(VlanId assignedVlan, ApplicationId applicationId) {
380 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
381 .matchVlanId(assignedVlan)
382 .matchEthType(Ethernet.TYPE_IPV6)
383 .matchIPProtocol(PROTOCOL_ICMP6);
384 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
385 .popVlan()
386 .punt();
387
388 return DefaultFlowRule.builder()
389 .forDevice(deviceId)
390 .withSelector(sbuilder.build())
391 .withTreatment(tbuilder.build())
392 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
393 .fromApp(applicationId)
394 .makePermanent()
395 .forTable(ACL_TABLE).build();
396 }
397
Saurav Das4ce45962015-11-24 23:21:05 -0800398 /*
399 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
400 * Workaround requires popping off the VLAN tags in the TMAC table.
401 *
402 * (non-Javadoc)
403 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
404 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800405 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800406 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das4ce45962015-11-24 23:21:05 -0800407 EthCriterion ethCriterion,
408 VlanIdCriterion vidCriterion,
409 VlanId assignedVlan,
Charles Chand57552d2018-03-02 15:41:41 -0800410 MacAddress unicastMac,
Saurav Das4ce45962015-11-24 23:21:05 -0800411 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800412 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
413 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
414 return processEthDstOnlyFilter(ethCriterion, applicationId);
415 }
416
Charles Chan5b9df8d2016-03-28 22:21:40 -0700417 // Multicast MAC
418 if (ethCriterion.mask() != null) {
Charles Chand57552d2018-03-02 15:41:41 -0800419 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700420 }
421
Saurav Das4ce45962015-11-24 23:21:05 -0800422 //handling untagged packets via assigned VLAN
423 if (vidCriterion.vlanId() == VlanId.NONE) {
424 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
425 }
426 // ofdpa cannot match on ALL portnumber, so we need to use separate
427 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800428 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800429 if (portCriterion != null) {
430 if (portCriterion.port() == PortNumber.ALL) {
431 for (Port port : deviceService.getPorts(deviceId)) {
432 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
433 portnums.add(port.number());
434 }
Saurav Das4ce45962015-11-24 23:21:05 -0800435 }
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800436 } else {
437 portnums.add(portCriterion.port());
Saurav Das4ce45962015-11-24 23:21:05 -0800438 }
Saurav Das4ce45962015-11-24 23:21:05 -0800439 }
440
Charles Chan93090352018-03-02 13:26:22 -0800441 List<FlowRule> rules = new ArrayList<>();
Saurav Das4ce45962015-11-24 23:21:05 -0800442 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800443 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800444 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
445 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
446 selector.matchInPort(pnum);
447 selector.matchVlanId(vidCriterion.vlanId());
448 selector.matchEthType(Ethernet.TYPE_IPV4);
449 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800450 if (!supportTaggedMpls()) {
451 treatment.popVlan();
452 }
Saurav Das4ce45962015-11-24 23:21:05 -0800453 treatment.transition(UNICAST_ROUTING_TABLE);
454 FlowRule rule = DefaultFlowRule.builder()
455 .forDevice(deviceId)
456 .withSelector(selector.build())
457 .withTreatment(treatment.build())
458 .withPriority(DEFAULT_PRIORITY)
459 .fromApp(applicationId)
460 .makePermanent()
461 .forTable(TMAC_TABLE).build();
462 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800463
464 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800465 selector = DefaultTrafficSelector.builder();
466 treatment = DefaultTrafficTreatment.builder();
467 selector.matchInPort(pnum);
468 selector.matchVlanId(vidCriterion.vlanId());
469 selector.matchEthType(Ethernet.MPLS_UNICAST);
470 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800471 if (!supportTaggedMpls()) {
472 treatment.popVlan();
473 }
Saurav Das4ce45962015-11-24 23:21:05 -0800474 treatment.transition(MPLS_TABLE_0);
475 rule = DefaultFlowRule.builder()
476 .forDevice(deviceId)
477 .withSelector(selector.build())
478 .withTreatment(treatment.build())
479 .withPriority(DEFAULT_PRIORITY)
480 .fromApp(applicationId)
481 .makePermanent()
482 .forTable(TMAC_TABLE).build();
483 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800484
485 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800486 selector = DefaultTrafficSelector.builder();
487 treatment = DefaultTrafficTreatment.builder();
488 selector.matchInPort(pnum);
489 selector.matchVlanId(vidCriterion.vlanId());
490 selector.matchEthType(Ethernet.TYPE_IPV6);
491 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800492 if (!supportTaggedMpls()) {
493 treatment.popVlan();
494 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800495 treatment.transition(UNICAST_ROUTING_TABLE);
496 rule = DefaultFlowRule.builder()
497 .forDevice(deviceId)
498 .withSelector(selector.build())
499 .withTreatment(treatment.build())
500 .withPriority(DEFAULT_PRIORITY)
501 .fromApp(applicationId)
502 .makePermanent()
503 .forTable(TMAC_TABLE).build();
504 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800505 }
Charles Chan206506b2018-03-02 16:43:28 -0800506 return ImmutableList.of(rules);
Saurav Das4ce45962015-11-24 23:21:05 -0800507 }
508
Charles Chan5270ed02016-01-30 23:22:37 -0800509 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800510 protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700511 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800512 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
513 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
514 selector.matchEthType(Ethernet.TYPE_IPV4);
515 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800516 if (!supportTaggedMpls()) {
517 treatment.popVlan();
518 }
Charles Chan5270ed02016-01-30 23:22:37 -0800519 treatment.transition(UNICAST_ROUTING_TABLE);
520 FlowRule rule = DefaultFlowRule.builder()
521 .forDevice(deviceId)
522 .withSelector(selector.build())
523 .withTreatment(treatment.build())
524 .withPriority(DEFAULT_PRIORITY)
525 .fromApp(applicationId)
526 .makePermanent()
527 .forTable(TMAC_TABLE).build();
Charles Chan206506b2018-03-02 16:43:28 -0800528 return ImmutableList.of(ImmutableList.of(rule));
Charles Chan5270ed02016-01-30 23:22:37 -0800529 }
530
Saurav Das4ce45962015-11-24 23:21:05 -0800531 /*
532 * Cpqd emulation allows MPLS ecmp.
533 *
534 * (non-Javadoc)
535 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
536 */
537 @Override
538 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800539 TrafficSelector selector = fwd.selector();
540 EthTypeCriterion ethType =
541 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
542 if ((ethType == null) ||
543 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800544 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
545 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800546 log.warn("processSpecific: Unsupported forwarding objective criteria"
547 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800548 fail(fwd, ObjectiveError.UNSUPPORTED);
549 return Collections.emptySet();
550 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800551 boolean defaultRule = false;
Charles Chan93090352018-03-02 13:26:22 -0800552 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800553 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800554 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
555
Saurav Das8a0732e2015-11-20 15:27:53 -0800556 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800557 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700558 if (ipv4Dst.isMulticast()) {
559 if (ipv4Dst.prefixLength() != 32) {
560 log.warn("Multicast specific forwarding objective can only be /32");
561 fail(fwd, ObjectiveError.BADPARAMS);
562 return ImmutableSet.of();
563 }
564 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
565 if (assignedVlan == null) {
566 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
567 fail(fwd, ObjectiveError.BADPARAMS);
568 return ImmutableSet.of();
569 }
570 filteredSelector.matchVlanId(assignedVlan);
571 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
572 forTableId = MULTICAST_ROUTING_TABLE;
573 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
574 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800575 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700576 if (ipv4Dst.prefixLength() == 0) {
577 // The entire IPV4_DST field is wildcarded intentionally
578 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700579 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700580 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700581 }
582 forTableId = UNICAST_ROUTING_TABLE;
583 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
584 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800585 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800586 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
Julia Ferguson65428c32017-08-10 18:15:24 +0000587 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
588 if (ipv6Dst.isMulticast()) {
589 if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
590 log.debug("Multicast specific IPv6 forwarding objective can only be /128");
591 fail(fwd, ObjectiveError.BADPARAMS);
592 return ImmutableSet.of();
593 }
594 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
595 if (assignedVlan == null) {
596 log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
597 fail(fwd, ObjectiveError.BADPARAMS);
598 return ImmutableSet.of();
599 }
600 filteredSelector.matchVlanId(assignedVlan);
601 filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
602 forTableId = MULTICAST_ROUTING_TABLE;
603 log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
604 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
605 } else {
606 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
607 return Collections.emptyList();
608 }
609 forTableId = UNICAST_ROUTING_TABLE;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800610 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800611 } else {
612 filteredSelector
613 .matchEthType(Ethernet.MPLS_UNICAST)
614 .matchMplsLabel(((MplsCriterion)
615 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
616 MplsBosCriterion bos = (MplsBosCriterion) selector
617 .getCriterion(Criterion.Type.MPLS_BOS);
618 if (bos != null) {
619 filteredSelector.matchMplsBos(bos.mplsBos());
620 }
621 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800622 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
623 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800624 }
625
626 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
627 if (fwd.treatment() != null) {
628 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan40132b32017-01-22 00:19:37 -0800629 if (!supportCopyTtl() && i instanceof L3ModificationInstruction) {
630 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
631 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
632 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
633 continue;
634 }
635 }
Charles Chan7d10b162015-12-07 18:54:45 -0800636 /*
637 * NOTE: OF-DPA does not support immediate instruction in
638 * L3 unicast and MPLS table.
639 */
640 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800641 }
642 }
643
644 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800645 NextGroup next = getGroupForNextObjective(fwd.nextId());
646 if (next != null) {
647 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
648 // we only need the top level group's key to point the flow to it
649 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
650 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700651 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
652 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800653 fail(fwd, ObjectiveError.GROUPMISSING);
654 return Collections.emptySet();
655 }
656 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800657 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800658 }
659 tb.transition(ACL_TABLE);
660 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
661 .fromApp(fwd.appId())
662 .withPriority(fwd.priority())
663 .forDevice(deviceId)
664 .withSelector(filteredSelector.build())
665 .withTreatment(tb.build())
666 .forTable(forTableId);
667
668 if (fwd.permanent()) {
669 ruleBuilder.makePermanent();
670 } else {
671 ruleBuilder.makeTemporary(fwd.timeout());
672 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800673 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
674 flowRuleCollection.add(ruleBuilder.build());
675 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800676 flowRuleCollection.add(
677 defaultRoute(fwd, complementarySelector, forTableId, tb)
678 );
Flavio Castroe10fa242016-01-15 12:43:51 -0800679 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
680 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800681 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800682 }
683
Charles Chan1e492d32016-01-30 23:22:37 -0800684 @Override
685 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
686 List<FlowRule> rules = new ArrayList<>();
687
688 // Build filtered selector
689 TrafficSelector selector = fwd.selector();
690 EthCriterion ethCriterion = (EthCriterion) selector
691 .getCriterion(Criterion.Type.ETH_DST);
692 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
693 .getCriterion(Criterion.Type.VLAN_VID);
694
695 if (vlanIdCriterion == null) {
696 log.warn("Forwarding objective for bridging requires vlan. Not "
697 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
698 fail(fwd, ObjectiveError.BADPARAMS);
699 return Collections.emptySet();
700 }
701
702 TrafficSelector.Builder filteredSelectorBuilder =
703 DefaultTrafficSelector.builder();
704 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -0800705 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -0800706 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
707 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
708 fwd.id(), fwd.nextId(), deviceId);
709 } else {
710 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
711 + "in dev:{} for vlan:{}",
712 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
713 }
714 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
715 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
716
717 if (fwd.treatment() != null) {
718 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
719 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
720 }
721
722 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
723 if (fwd.nextId() != null) {
724 NextGroup next = getGroupForNextObjective(fwd.nextId());
725 if (next != null) {
726 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
727 // we only need the top level group's key to point the flow to it
728 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
729 if (group != null) {
730 treatmentBuilder.deferred().group(group.id());
731 } else {
732 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
733 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
734 fail(fwd, ObjectiveError.GROUPMISSING);
735 return Collections.emptySet();
736 }
737 }
738 }
739 treatmentBuilder.immediate().transition(ACL_TABLE);
740 TrafficTreatment filteredTreatment = treatmentBuilder.build();
741
742 // Build bridging table entries
743 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
744 flowRuleBuilder.fromApp(fwd.appId())
745 .withPriority(fwd.priority())
746 .forDevice(deviceId)
747 .withSelector(filteredSelector)
748 .withTreatment(filteredTreatment)
749 .forTable(BRIDGING_TABLE);
750 if (fwd.permanent()) {
751 flowRuleBuilder.makePermanent();
752 } else {
753 flowRuleBuilder.makeTemporary(fwd.timeout());
754 }
755 rules.add(flowRuleBuilder.build());
756 return rules;
757 }
758
Saurav Das52025962016-01-28 22:30:01 -0800759 /*
760 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
761 * ACL table. Because we pop off vlan tags in TMAC table,
762 * we need to avoid matching on vlans in the ACL table.
763 */
764 @Override
765 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
766 log.info("Processing versatile forwarding objective");
767
Saurav Das52025962016-01-28 22:30:01 -0800768 if (fwd.nextId() == null && fwd.treatment() == null) {
769 log.error("Forwarding objective {} from {} must contain "
770 + "nextId or Treatment", fwd.selector(), fwd.appId());
771 return Collections.emptySet();
772 }
773
774 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
775 fwd.selector().criteria().forEach(criterion -> {
776 if (criterion instanceof VlanIdCriterion) {
777 // avoid matching on vlans
778 return;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800779 } else if (criterion instanceof Icmpv6TypeCriterion ||
780 criterion instanceof Icmpv6CodeCriterion) {
781 /*
782 * We silenty discard these criterions, our current
783 * OFDPA platform does not support these matches on
784 * the ACL table.
785 */
786 log.warn("ICMPv6 Type and ICMPv6 Code are not supported");
Saurav Das52025962016-01-28 22:30:01 -0800787 } else {
788 sbuilder.add(criterion);
789 }
790 });
791
792 // XXX driver does not currently do type checking as per Tables 65-67 in
793 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
794 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
795 if (fwd.treatment() != null) {
796 for (Instruction ins : fwd.treatment().allInstructions()) {
797 if (ins instanceof OutputInstruction) {
798 OutputInstruction o = (OutputInstruction) ins;
799 if (o.port() == PortNumber.CONTROLLER) {
Charles Chan0f43e472017-02-14 14:00:16 -0800800 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -0800801 } else {
802 log.warn("Only allowed treatments in versatile forwarding "
803 + "objectives are punts to the controller");
804 }
Charles Chan3fe71712018-06-15 18:54:18 -0700805 } else if (ins instanceof NoActionInstruction) {
806 // No action is allowed and nothing needs to be done
Saurav Das52025962016-01-28 22:30:01 -0800807 } else {
808 log.warn("Cannot process instruction in versatile fwd {}", ins);
809 }
810 }
Charles Chan2df0e8a2017-01-09 11:45:08 -0800811 if (fwd.treatment().clearedDeferred()) {
812 ttBuilder.wipeDeferred();
813 }
Saurav Das52025962016-01-28 22:30:01 -0800814 }
815 if (fwd.nextId() != null) {
816 // overide case
817 NextGroup next = getGroupForNextObjective(fwd.nextId());
818 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
819 // we only need the top level group's key to point the flow to it
820 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
821 if (group == null) {
822 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
823 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
824 fail(fwd, ObjectiveError.GROUPMISSING);
825 return Collections.emptySet();
826 }
827 ttBuilder.deferred().group(group.id());
828 }
829
830 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
831 .fromApp(fwd.appId())
832 .withPriority(fwd.priority())
833 .forDevice(deviceId)
834 .withSelector(sbuilder.build())
835 .withTreatment(ttBuilder.build())
836 .makePermanent()
837 .forTable(ACL_TABLE);
838 return Collections.singletonList(ruleBuilder.build());
839 }
840
841 /*
842 * Cpqd emulation requires table-miss-entries in forwarding tables.
843 * Real OFDPA does not require these rules as they are put in by default.
844 *
845 * (non-Javadoc)
846 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
847 */
Saurav Das2857f382015-11-03 14:39:27 -0800848 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700849 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -0800850 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
851 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
852 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
853 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
854 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
855 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
856 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
857 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
858 initTableMiss(ACL_TABLE, -1, null);
Charles Chan4e9620d2019-11-01 16:00:39 -0700859 initPuntTable();
Charles Chan0f43e472017-02-14 14:00:16 -0800860
861 if (supportPuntGroup()) {
Charles Chan0f43e472017-02-14 14:00:16 -0800862 initPopVlanPuntGroup();
863 } else {
864 initTableMiss(PUNT_TABLE, -1,
865 DefaultTrafficTreatment.builder().popVlan().punt().build());
866 }
Saurav Das558afec2015-05-31 17:12:48 -0700867 }
868
Charles Chanf6ec1532017-02-08 16:10:40 -0800869 /**
870 * Install table-miss flow entry.
871 *
872 * If treatment exists, use it directly.
873 * Else if treatment does not exist but nextTable > 0, transit to next table.
874 * Else apply empty treatment.
875 *
876 * @param thisTable this table ID
877 * @param nextTable next table ID
878 * @param treatment traffic treatment to apply.
879 */
880 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -0700881 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -0800882 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -0700883
Charles Chanf6ec1532017-02-08 16:10:40 -0800884 if (treatment == null) {
885 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
886 if (nextTable > 0) {
887 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -0700888 }
Charles Chanf6ec1532017-02-08 16:10:40 -0800889 treatment = tBuilder.build();
890 }
Saurav Das558afec2015-05-31 17:12:48 -0700891
Charles Chanb7504392017-02-10 12:51:04 -0800892 FlowRule rule = DefaultFlowRule.builder()
893 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -0800894 .withSelector(selector)
895 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -0800896 .withPriority(LOWEST_PRIORITY)
897 .fromApp(driverId)
898 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -0800899 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -0800900 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -0800901
902 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
903 @Override
904 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800905 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800906 }
Saurav Das2857f382015-11-03 14:39:27 -0800907 @Override
908 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800909 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800910 }
911 }));
912 }
Charles Chan0f43e472017-02-14 14:00:16 -0800913
914 /**
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700915 * Install lldp/bbdp matching rules at table PUNT_TABLE
916 * that forward traffic to controller.
917 *
918 */
Charles Chan4e9620d2019-11-01 16:00:39 -0700919 private void initPuntTable() {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700920 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
921 TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build();
922
Charles Chan4e9620d2019-11-01 16:00:39 -0700923 // Add punt rule for LLDP and BDDP
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700924 TrafficSelector.Builder lldpSelector = DefaultTrafficSelector.builder();
925 lldpSelector.matchEthType(EthType.EtherType.LLDP.ethType().toShort());
926 FlowRule lldpRule = DefaultFlowRule.builder()
927 .forDevice(deviceId)
928 .withSelector(lldpSelector.build())
929 .withTreatment(treatment)
930 .withPriority(HIGHEST_PRIORITY)
931 .fromApp(driverId)
932 .makePermanent()
933 .forTable(PUNT_TABLE).build();
934 ops = ops.add(lldpRule);
935
936 TrafficSelector.Builder bbdpSelector = DefaultTrafficSelector.builder();
937 bbdpSelector.matchEthType(EthType.EtherType.BDDP.ethType().toShort());
938 FlowRule bbdpRule = DefaultFlowRule.builder()
939 .forDevice(deviceId)
940 .withSelector(bbdpSelector.build())
941 .withTreatment(treatment)
942 .withPriority(HIGHEST_PRIORITY)
943 .fromApp(driverId)
944 .makePermanent()
945 .forTable(PUNT_TABLE).build();
946 ops.add(bbdpRule);
947
948 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
949 @Override
950 public void onSuccess(FlowRuleOperations ops) {
Charles Chan4e9620d2019-11-01 16:00:39 -0700951 log.info("Initialized table {} on {}", PUNT_TABLE, deviceId);
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700952 }
953 @Override
954 public void onError(FlowRuleOperations ops) {
Charles Chan4e9620d2019-11-01 16:00:39 -0700955 log.warn("Failed to initialize table {} on {}", PUNT_TABLE, deviceId);
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700956 }
957 }));
958 }
959
960 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800961 * Builds a indirect group contains pop_vlan and punt actions.
962 * <p>
963 * Using group instead of immediate action to ensure that
964 * the copy of packet on the data plane is not affected by the pop vlan action.
965 */
966 private void initPopVlanPuntGroup() {
Yi Tsengef19de12017-04-24 11:33:05 -0700967 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -0800968 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
969 .popVlan().punt().build();
970 GroupBucket bucket =
971 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
972 GroupDescription groupDesc =
973 new DefaultGroupDescription(
974 deviceId,
975 GroupDescription.Type.INDIRECT,
976 new GroupBuckets(Collections.singletonList(bucket)),
977 groupKey,
978 POP_VLAN_PUNT_GROUP_ID,
979 driverId);
980 groupService.addGroup(groupDesc);
981
982 log.info("Initialized pop vlan punt group on {}", deviceId);
983 }
Yi Tsengef19de12017-04-24 11:33:05 -0700984
985 /**
986 * Generates group key for a static indirect group that pop vlan and punt to
987 * controller.
988 *
989 * @return the group key of the indirect table
990 */
991 private GroupKey popVlanPuntGroupKey() {
992 int hash = POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_BIT_MASK);
993 return new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(hash));
994 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700995
996 private class PopVlanPuntGroupChecker implements Runnable {
997 @Override
998 public void run() {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700999 try {
1000 groupCheckerLock.lock();
1001 // this can happen outside of the lock but I think it is safer
1002 // to include it here.
1003 Group group = groupService.getGroup(deviceId, popVlanPuntGroupKey());
1004 if (group != null) {
1005 log.debug("PopVlanPuntGroupChecker: Installing {} missing rules at punt table.",
1006 flowRuleQueue.size());
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001007
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -07001008 // if we have pending flow rules install them
1009 if (flowRuleQueue.size() > 0) {
1010 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1011 // we should not care about the context here, it can only be add
1012 // since when removing the rules the group should be there already.
1013 flowRuleQueue.forEach(ops::add);
1014 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1015 @Override
1016 public void onSuccess(FlowRuleOperations ops) {
1017 log.debug("Applied {} pop vlan punt rules in device {}",
1018 ops.stages().get(0).size(), deviceId);
1019 }
1020
1021 @Override
1022 public void onError(FlowRuleOperations ops) {
1023 log.error("Failed to apply all pop vlan punt rules in dev {}", deviceId);
1024 }
1025 }));
1026 }
1027 // this signifies that the group is created and now
1028 // flow rules can be installed directly
1029 flowRuleQueue = null;
pier4d7fd092020-01-23 11:59:56 +01001030 // Schedule with an initial delay the miss table flow rule installation
1031 // the delay is to make sure the queued flows are all installed before
1032 // pushing the table miss flow rule
1033 // TODO it can be further optimized by using context and completable future
1034 groupChecker.schedule(new TableMissFlowInstaller(), 5000, TimeUnit.MILLISECONDS);
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001035 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -07001036 } finally {
1037 groupCheckerLock.unlock();
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001038 }
1039 }
1040 }
pier4d7fd092020-01-23 11:59:56 +01001041
1042 private class TableMissFlowInstaller implements Runnable {
1043 @Override
1044 public void run() {
1045 // Add table miss flow rule
1046 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1047 TrafficSelector.Builder defaultSelector = DefaultTrafficSelector.builder();
1048 TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build();
1049 FlowRule defaultRule = DefaultFlowRule.builder()
1050 .forDevice(deviceId)
1051 .withSelector(defaultSelector.build())
1052 .withTreatment(treatment)
1053 .withPriority(LOWEST_PRIORITY)
1054 .fromApp(driverId)
1055 .makePermanent()
1056 .forTable(PUNT_TABLE).build();
1057 ops.add(defaultRule);
1058 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1059 @Override
1060 public void onSuccess(FlowRuleOperations ops) {
1061 log.info("Initialized table miss flow rule {} on {}", PUNT_TABLE, deviceId);
1062 }
1063 @Override
1064 public void onError(FlowRuleOperations ops) {
1065 log.warn("Failed to initialize table miss flow rule {} on {}", PUNT_TABLE, deviceId);
1066 }
1067 }));
1068 // shutdown the group checker gracefully
1069 groupChecker.shutdown();
1070 }
1071 }
Saurav Das558afec2015-05-31 17:12:48 -07001072}