blob: 72b2e8ae660c25d8cd3d71b5639281d951809e4b [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.*;
Jonathan Hart855179c2016-04-26 07:40:04 -070087import static org.slf4j.LoggerFactory.getLogger;
88
Saurav Das558afec2015-05-31 17:12:48 -070089
90/**
Charles Chan40132b32017-01-22 00:19:37 -080091 * Driver for software switch emulation of the OFDPA pipeline.
Saurav Das52025962016-01-28 22:30:01 -080092 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
93 * does not handle vlan tags and mpls labels simultaneously, which requires us
94 * to do some workarounds in the driver. This driver is meant for the use of
95 * the cpqd switch when MPLS is required. As a result this driver works only
96 * on incoming untagged packets.
Saurav Das558afec2015-05-31 17:12:48 -070097 */
Charles Chan361154b2016-03-24 10:23:39 -070098public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -070099
100 private final Logger log = getLogger(getClass());
101
Charles Chan40132b32017-01-22 00:19:37 -0800102 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800103 * Table that determines whether VLAN is popped before punting to controller.
104 * <p>
105 * This is a non-OFDPA table to emulate OFDPA packet in behavior.
106 * VLAN will be popped before punting if the VLAN is internally assigned.
107 * <p>
108 * Also note that 63 is the max table number in CpqD.
109 */
110 private static final int PUNT_TABLE = 63;
111
112 /**
113 * A static indirect group that pop vlan and punt to controller.
114 * <p>
115 * The purpose of using a group instead of immediate action is that this
116 * won't affect another copy on the data plane when write action exists.
117 */
118 private static final int POP_VLAN_PUNT_GROUP_ID = 0xc0000000;
119
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700120 /**
121 * Executor for group checker thread that checks pop vlan punt group.
122 */
123 private ScheduledExecutorService groupChecker;
124
125 /**
126 * Queue for passing pop vlan punt group flow rules to the GroupChecker thread.
127 */
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700128 private Queue<FlowRule> flowRuleQueue;
129
130 /**
131 * Lock used in synchronizing driver thread with groupCheckerThread.
132 */
133 private ReentrantLock groupCheckerLock;
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700134
Charles Chan053b1cb2017-03-22 16:56:35 -0700135 @Override
136 protected boolean requireVlanExtensions() {
137 return false;
138 }
139
Charles Chan0f43e472017-02-14 14:00:16 -0800140 /**
Charles Chan40132b32017-01-22 00:19:37 -0800141 * Determines whether this pipeline support copy ttl instructions or not.
142 *
143 * @return true if copy ttl instructions are supported
144 */
145 protected boolean supportCopyTtl() {
146 return true;
147 }
148
Charles Chan0f43e472017-02-14 14:00:16 -0800149 /**
150 * Determines whether this pipeline support push mpls to vlan-tagged packets or not.
151 * <p>
152 * If not support, pop vlan before push entering unicast and mpls table.
153 * Side effect: HostService learns redundant hosts with same MAC but
154 * different VLAN. No known side effect on the network reachability.
155 *
156 * @return true if push mpls to vlan-tagged packets is supported
157 */
158 protected boolean supportTaggedMpls() {
159 return false;
160 }
161
162 /**
163 * Determines whether this pipeline support punt action in group bucket.
164 *
165 * @return true if punt action in group bucket is supported
166 */
167 protected boolean supportPuntGroup() {
168 return false;
169 }
170
Charles Chan425854b2016-04-11 15:32:12 -0700171 @Override
Charles Chan40132b32017-01-22 00:19:37 -0800172 protected void initDriverId() {
Charles Chan425854b2016-04-11 15:32:12 -0700173 driverId = coreService.registerApplication(
174 "org.onosproject.driver.CpqdOfdpa2Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -0800175 }
Charles Chan425854b2016-04-11 15:32:12 -0700176
Charles Chan40132b32017-01-22 00:19:37 -0800177 @Override
178 protected void initGroupHander(PipelinerContext context) {
179 groupHandler = new CpqdOfdpa2GroupHandler();
180 groupHandler.init(deviceId, context);
Charles Chan425854b2016-04-11 15:32:12 -0700181 }
182
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700183 @Override
184 public void init(DeviceId deviceId, PipelinerContext context) {
185
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700186 if (supportPuntGroup()) {
187 // create a new executor at each init and a new empty queue
188 groupChecker = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/driver",
189 "cpqd-ofdpa-%d", log));
190 flowRuleQueue = new ConcurrentLinkedQueue<>();
191 groupCheckerLock = new ReentrantLock();
192 groupChecker.scheduleAtFixedRate(new PopVlanPuntGroupChecker(), 20, 50, TimeUnit.MILLISECONDS);
193 super.init(deviceId, context);
194 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700195 }
Saurav Das4ce45962015-11-24 23:21:05 -0800196 /*
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700197 * Cpqd emulation does not require the non OF-standard rules for
198 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800199 *
200 * (non-Javadoc)
201 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
202 */
Saurav Das558afec2015-05-31 17:12:48 -0700203 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800204 protected List<List<FlowRule>> processVlanIdFilter(PortCriterion portCriterion,
Saurav Das2857f382015-11-03 14:39:27 -0800205 VlanIdCriterion vidCriterion,
206 VlanId assignedVlan,
207 ApplicationId applicationId) {
Charles Chan79769232016-07-05 16:34:39 -0700208 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800209 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
210 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
211 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800212 treatment.transition(TMAC_TABLE);
213
Saurav Das2857f382015-11-03 14:39:27 -0800214 if (vidCriterion.vlanId() == VlanId.NONE) {
215 // untagged packets are assigned vlans
216 treatment.pushVlan().setVlanId(assignedVlan);
Pier3cc7e662018-03-07 11:42:50 +0100217 } else if (!vidCriterion.vlanId().equals(assignedVlan)) {
218 // Rewrite with assigned vlans
219 treatment.setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800220 }
Saurav Das2857f382015-11-03 14:39:27 -0800221
222 // ofdpa cannot match on ALL portnumber, so we need to use separate
223 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800224 List<PortNumber> portnums = new ArrayList<>();
Ray Milkey94542b02018-05-10 12:42:51 -0700225 if (portCriterion != null) {
226 if (portCriterion.port() == PortNumber.ALL) {
227 for (Port port : deviceService.getPorts(deviceId)) {
228 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
229 portnums.add(port.number());
230 }
Saurav Das2857f382015-11-03 14:39:27 -0800231 }
Ray Milkey94542b02018-05-10 12:42:51 -0700232 } else {
233 portnums.add(portCriterion.port());
Saurav Das2857f382015-11-03 14:39:27 -0800234 }
Saurav Das2857f382015-11-03 14:39:27 -0800235 }
Saurav Das4f980082015-11-05 13:39:15 -0800236
Saurav Das2857f382015-11-03 14:39:27 -0800237 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800238 // NOTE: Emulating OFDPA behavior by popping off internal assigned
239 // VLAN before sending to controller
240 if (supportPuntGroup() && vidCriterion.vlanId() == VlanId.NONE) {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700241 try {
242 groupCheckerLock.lock();
243 if (flowRuleQueue == null) {
244 // this means that the group has been created
245 // and that groupChecker has destroyed the queue
246 log.debug("Installing punt table rule for untagged port {} and vlan {}.",
247 pnum, assignedVlan);
248 rules.add(buildPuntTableRule(pnum, assignedVlan));
249 } else {
250 // The VLAN punt group may be held back due to device initial audit.
251 // In that case, we queue all punt table flow until the group has been created.
252 log.debug("popVlanPuntGroup not found in dev:{}, queueing this flow rule.", deviceId);
253 flowRuleQueue.add(buildPuntTableRule(pnum, assignedVlan));
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700254 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700255 } finally {
256 groupCheckerLock.unlock();
Charles Chan0f43e472017-02-14 14:00:16 -0800257 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700258 } else if (vidCriterion.vlanId() != VlanId.NONE) {
259 // for tagged ports just forward to the controller
260 log.debug("Installing punt rule for tagged port {} and vlan {}.", pnum, vidCriterion.vlanId());
261 rules.add(buildPuntTableRuleTagged(pnum, vidCriterion.vlanId()));
Charles Chan0f43e472017-02-14 14:00:16 -0800262 }
263
Saurav Das4f980082015-11-05 13:39:15 -0800264 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800265 selector.matchInPort(pnum);
266 FlowRule rule = DefaultFlowRule.builder()
267 .forDevice(deviceId)
268 .withSelector(selector.build())
269 .withTreatment(treatment.build())
270 .withPriority(DEFAULT_PRIORITY)
271 .fromApp(applicationId)
272 .makePermanent()
273 .forTable(VLAN_TABLE).build();
274 rules.add(rule);
275 }
Charles Chanf57a8252016-06-29 19:12:37 -0700276
Charles Chan206506b2018-03-02 16:43:28 -0800277 return ImmutableList.of(rules);
Saurav Das2857f382015-11-03 14:39:27 -0800278 }
279
Pier Ventree0ae7a32016-11-23 09:57:42 -0800280 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800281 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
282 * a group that pop vlan and punt.
283 *
284 * @param portNumber port number
285 * @param assignedVlan internally assigned vlan id
286 * @return punt table flow rule
287 */
288 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
289 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
290 .matchInPort(portNumber)
291 .matchVlanId(assignedVlan);
292 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
Yi Tsengfa394de2017-02-01 11:26:40 -0800293 .group(new GroupId(POP_VLAN_PUNT_GROUP_ID));
Charles Chan0f43e472017-02-14 14:00:16 -0800294
295 return DefaultFlowRule.builder()
296 .forDevice(deviceId)
297 .withSelector(sbuilder.build())
298 .withTreatment(tbuilder.build())
299 .withPriority(PacketPriority.CONTROL.priorityValue())
300 .fromApp(driverId)
301 .makePermanent()
302 .forTable(PUNT_TABLE).build();
303 }
304
305 /**
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700306 * Creates punt table entry that matches IN_PORT and VLAN_VID and forwards
307 * packet to controller tagged.
308 *
309 * @param portNumber port number
310 * @param packetVlan vlan tag of the packet
311 * @return punt table flow rule
312 */
313 private FlowRule buildPuntTableRuleTagged(PortNumber portNumber, VlanId packetVlan) {
314 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
315 .matchInPort(portNumber)
316 .matchVlanId(packetVlan);
317 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder().punt();
318
319 return DefaultFlowRule.builder()
320 .forDevice(deviceId)
321 .withSelector(sbuilder.build())
322 .withTreatment(tbuilder.build())
323 .withPriority(PacketPriority.CONTROL.priorityValue())
324 .fromApp(driverId)
325 .makePermanent()
326 .forTable(PUNT_TABLE).build();
327 }
328
329 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800330 * Builds a punt to the controller rule for the arp protocol.
Charles Chan0f43e472017-02-14 14:00:16 -0800331 * <p>
332 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
333 * pop VLAN before sending to controller disregarding whether
334 * it's an internally assigned VLAN or a natural VLAN.
335 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800336 *
337 * @param assignedVlan the internal assigned vlan id
338 * @param applicationId the application id
339 * @return the punt flow rule for the arp
340 */
341 private FlowRule buildArpPunt(VlanId assignedVlan, ApplicationId applicationId) {
342 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
343 .matchEthType(Ethernet.TYPE_ARP)
344 .matchVlanId(assignedVlan);
345 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
346 .popVlan()
347 .punt();
348
349 return DefaultFlowRule.builder()
350 .forDevice(deviceId)
351 .withSelector(sbuilder.build())
352 .withTreatment(tbuilder.build())
353 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
354 .fromApp(applicationId)
355 .makePermanent()
356 .forTable(ACL_TABLE).build();
357 }
358
359 /**
360 * Builds a punt to the controller rule for the icmp v6 messages.
Charles Chan0f43e472017-02-14 14:00:16 -0800361 * <p>
362 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
363 * pop VLAN before sending to controller disregarding whether
364 * it's an internally assigned VLAN or a natural VLAN.
365 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800366 *
367 * @param assignedVlan the internal assigned vlan id
368 * @param applicationId the application id
369 * @return the punt flow rule for the icmp v6 messages
370 */
371 private FlowRule buildIcmpV6Punt(VlanId assignedVlan, ApplicationId applicationId) {
372 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
373 .matchVlanId(assignedVlan)
374 .matchEthType(Ethernet.TYPE_IPV6)
375 .matchIPProtocol(PROTOCOL_ICMP6);
376 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
377 .popVlan()
378 .punt();
379
380 return DefaultFlowRule.builder()
381 .forDevice(deviceId)
382 .withSelector(sbuilder.build())
383 .withTreatment(tbuilder.build())
384 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
385 .fromApp(applicationId)
386 .makePermanent()
387 .forTable(ACL_TABLE).build();
388 }
389
Saurav Das4ce45962015-11-24 23:21:05 -0800390 /*
391 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
392 * Workaround requires popping off the VLAN tags in the TMAC table.
393 *
394 * (non-Javadoc)
395 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
396 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800397 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800398 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das4ce45962015-11-24 23:21:05 -0800399 EthCriterion ethCriterion,
400 VlanIdCriterion vidCriterion,
401 VlanId assignedVlan,
Charles Chand57552d2018-03-02 15:41:41 -0800402 MacAddress unicastMac,
Saurav Das4ce45962015-11-24 23:21:05 -0800403 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800404 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
405 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
406 return processEthDstOnlyFilter(ethCriterion, applicationId);
407 }
408
Charles Chan5b9df8d2016-03-28 22:21:40 -0700409 // Multicast MAC
410 if (ethCriterion.mask() != null) {
Charles Chand57552d2018-03-02 15:41:41 -0800411 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700412 }
413
Saurav Das4ce45962015-11-24 23:21:05 -0800414 //handling untagged packets via assigned VLAN
415 if (vidCriterion.vlanId() == VlanId.NONE) {
416 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
417 }
418 // ofdpa cannot match on ALL portnumber, so we need to use separate
419 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800420 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800421 if (portCriterion != null) {
422 if (portCriterion.port() == PortNumber.ALL) {
423 for (Port port : deviceService.getPorts(deviceId)) {
424 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
425 portnums.add(port.number());
426 }
Saurav Das4ce45962015-11-24 23:21:05 -0800427 }
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800428 } else {
429 portnums.add(portCriterion.port());
Saurav Das4ce45962015-11-24 23:21:05 -0800430 }
Saurav Das4ce45962015-11-24 23:21:05 -0800431 }
432
Charles Chan93090352018-03-02 13:26:22 -0800433 List<FlowRule> rules = new ArrayList<>();
Saurav Das4ce45962015-11-24 23:21:05 -0800434 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800435 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800436 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
437 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
438 selector.matchInPort(pnum);
439 selector.matchVlanId(vidCriterion.vlanId());
440 selector.matchEthType(Ethernet.TYPE_IPV4);
441 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800442 if (!supportTaggedMpls()) {
443 treatment.popVlan();
444 }
Saurav Das4ce45962015-11-24 23:21:05 -0800445 treatment.transition(UNICAST_ROUTING_TABLE);
446 FlowRule rule = DefaultFlowRule.builder()
447 .forDevice(deviceId)
448 .withSelector(selector.build())
449 .withTreatment(treatment.build())
450 .withPriority(DEFAULT_PRIORITY)
451 .fromApp(applicationId)
452 .makePermanent()
453 .forTable(TMAC_TABLE).build();
454 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800455
456 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800457 selector = DefaultTrafficSelector.builder();
458 treatment = DefaultTrafficTreatment.builder();
459 selector.matchInPort(pnum);
460 selector.matchVlanId(vidCriterion.vlanId());
461 selector.matchEthType(Ethernet.MPLS_UNICAST);
462 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800463 if (!supportTaggedMpls()) {
464 treatment.popVlan();
465 }
Saurav Das4ce45962015-11-24 23:21:05 -0800466 treatment.transition(MPLS_TABLE_0);
467 rule = DefaultFlowRule.builder()
468 .forDevice(deviceId)
469 .withSelector(selector.build())
470 .withTreatment(treatment.build())
471 .withPriority(DEFAULT_PRIORITY)
472 .fromApp(applicationId)
473 .makePermanent()
474 .forTable(TMAC_TABLE).build();
475 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800476
477 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800478 selector = DefaultTrafficSelector.builder();
479 treatment = DefaultTrafficTreatment.builder();
480 selector.matchInPort(pnum);
481 selector.matchVlanId(vidCriterion.vlanId());
482 selector.matchEthType(Ethernet.TYPE_IPV6);
483 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800484 if (!supportTaggedMpls()) {
485 treatment.popVlan();
486 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800487 treatment.transition(UNICAST_ROUTING_TABLE);
488 rule = DefaultFlowRule.builder()
489 .forDevice(deviceId)
490 .withSelector(selector.build())
491 .withTreatment(treatment.build())
492 .withPriority(DEFAULT_PRIORITY)
493 .fromApp(applicationId)
494 .makePermanent()
495 .forTable(TMAC_TABLE).build();
496 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800497 }
Charles Chan206506b2018-03-02 16:43:28 -0800498 return ImmutableList.of(rules);
Saurav Das4ce45962015-11-24 23:21:05 -0800499 }
500
Charles Chan5270ed02016-01-30 23:22:37 -0800501 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800502 protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700503 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800504 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
505 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
506 selector.matchEthType(Ethernet.TYPE_IPV4);
507 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800508 if (!supportTaggedMpls()) {
509 treatment.popVlan();
510 }
Charles Chan5270ed02016-01-30 23:22:37 -0800511 treatment.transition(UNICAST_ROUTING_TABLE);
512 FlowRule rule = DefaultFlowRule.builder()
513 .forDevice(deviceId)
514 .withSelector(selector.build())
515 .withTreatment(treatment.build())
516 .withPriority(DEFAULT_PRIORITY)
517 .fromApp(applicationId)
518 .makePermanent()
519 .forTable(TMAC_TABLE).build();
Charles Chan206506b2018-03-02 16:43:28 -0800520 return ImmutableList.of(ImmutableList.of(rule));
Charles Chan5270ed02016-01-30 23:22:37 -0800521 }
522
Saurav Das4ce45962015-11-24 23:21:05 -0800523 /*
524 * Cpqd emulation allows MPLS ecmp.
525 *
526 * (non-Javadoc)
527 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
528 */
529 @Override
530 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800531 TrafficSelector selector = fwd.selector();
532 EthTypeCriterion ethType =
533 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
534 if ((ethType == null) ||
535 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800536 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
537 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800538 log.warn("processSpecific: Unsupported forwarding objective criteria"
539 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800540 fail(fwd, ObjectiveError.UNSUPPORTED);
541 return Collections.emptySet();
542 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800543 boolean defaultRule = false;
Charles Chan93090352018-03-02 13:26:22 -0800544 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800545 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800546 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
547
Saurav Das8a0732e2015-11-20 15:27:53 -0800548 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800549 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700550 if (ipv4Dst.isMulticast()) {
551 if (ipv4Dst.prefixLength() != 32) {
552 log.warn("Multicast specific forwarding objective can only be /32");
553 fail(fwd, ObjectiveError.BADPARAMS);
554 return ImmutableSet.of();
555 }
556 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
557 if (assignedVlan == null) {
558 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
559 fail(fwd, ObjectiveError.BADPARAMS);
560 return ImmutableSet.of();
561 }
562 filteredSelector.matchVlanId(assignedVlan);
563 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
564 forTableId = MULTICAST_ROUTING_TABLE;
565 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
566 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800567 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700568 if (ipv4Dst.prefixLength() == 0) {
569 // The entire IPV4_DST field is wildcarded intentionally
570 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700571 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700572 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700573 }
574 forTableId = UNICAST_ROUTING_TABLE;
575 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
576 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800577 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800578 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
Julia Ferguson65428c32017-08-10 18:15:24 +0000579 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
580 if (ipv6Dst.isMulticast()) {
581 if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
582 log.debug("Multicast specific IPv6 forwarding objective can only be /128");
583 fail(fwd, ObjectiveError.BADPARAMS);
584 return ImmutableSet.of();
585 }
586 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
587 if (assignedVlan == null) {
588 log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
589 fail(fwd, ObjectiveError.BADPARAMS);
590 return ImmutableSet.of();
591 }
592 filteredSelector.matchVlanId(assignedVlan);
593 filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
594 forTableId = MULTICAST_ROUTING_TABLE;
595 log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
596 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
597 } else {
598 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
599 return Collections.emptyList();
600 }
601 forTableId = UNICAST_ROUTING_TABLE;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800602 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800603 } else {
604 filteredSelector
605 .matchEthType(Ethernet.MPLS_UNICAST)
606 .matchMplsLabel(((MplsCriterion)
607 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
608 MplsBosCriterion bos = (MplsBosCriterion) selector
609 .getCriterion(Criterion.Type.MPLS_BOS);
610 if (bos != null) {
611 filteredSelector.matchMplsBos(bos.mplsBos());
612 }
613 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800614 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
615 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800616 }
617
618 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
619 if (fwd.treatment() != null) {
620 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan40132b32017-01-22 00:19:37 -0800621 if (!supportCopyTtl() && i instanceof L3ModificationInstruction) {
622 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
623 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
624 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
625 continue;
626 }
627 }
Charles Chan7d10b162015-12-07 18:54:45 -0800628 /*
629 * NOTE: OF-DPA does not support immediate instruction in
630 * L3 unicast and MPLS table.
631 */
632 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800633 }
634 }
635
636 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800637 NextGroup next = getGroupForNextObjective(fwd.nextId());
638 if (next != null) {
639 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
640 // we only need the top level group's key to point the flow to it
641 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
642 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700643 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
644 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800645 fail(fwd, ObjectiveError.GROUPMISSING);
646 return Collections.emptySet();
647 }
648 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800649 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800650 }
651 tb.transition(ACL_TABLE);
652 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
653 .fromApp(fwd.appId())
654 .withPriority(fwd.priority())
655 .forDevice(deviceId)
656 .withSelector(filteredSelector.build())
657 .withTreatment(tb.build())
658 .forTable(forTableId);
659
660 if (fwd.permanent()) {
661 ruleBuilder.makePermanent();
662 } else {
663 ruleBuilder.makeTemporary(fwd.timeout());
664 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800665 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
666 flowRuleCollection.add(ruleBuilder.build());
667 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800668 flowRuleCollection.add(
669 defaultRoute(fwd, complementarySelector, forTableId, tb)
670 );
Flavio Castroe10fa242016-01-15 12:43:51 -0800671 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
672 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800673 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800674 }
675
Charles Chan1e492d32016-01-30 23:22:37 -0800676 @Override
677 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
678 List<FlowRule> rules = new ArrayList<>();
679
680 // Build filtered selector
681 TrafficSelector selector = fwd.selector();
682 EthCriterion ethCriterion = (EthCriterion) selector
683 .getCriterion(Criterion.Type.ETH_DST);
684 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
685 .getCriterion(Criterion.Type.VLAN_VID);
686
687 if (vlanIdCriterion == null) {
688 log.warn("Forwarding objective for bridging requires vlan. Not "
689 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
690 fail(fwd, ObjectiveError.BADPARAMS);
691 return Collections.emptySet();
692 }
693
694 TrafficSelector.Builder filteredSelectorBuilder =
695 DefaultTrafficSelector.builder();
696 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -0800697 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -0800698 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
699 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
700 fwd.id(), fwd.nextId(), deviceId);
701 } else {
702 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
703 + "in dev:{} for vlan:{}",
704 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
705 }
706 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
707 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
708
709 if (fwd.treatment() != null) {
710 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
711 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
712 }
713
714 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
715 if (fwd.nextId() != null) {
716 NextGroup next = getGroupForNextObjective(fwd.nextId());
717 if (next != null) {
718 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
719 // we only need the top level group's key to point the flow to it
720 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
721 if (group != null) {
722 treatmentBuilder.deferred().group(group.id());
723 } else {
724 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
725 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
726 fail(fwd, ObjectiveError.GROUPMISSING);
727 return Collections.emptySet();
728 }
729 }
730 }
731 treatmentBuilder.immediate().transition(ACL_TABLE);
732 TrafficTreatment filteredTreatment = treatmentBuilder.build();
733
734 // Build bridging table entries
735 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
736 flowRuleBuilder.fromApp(fwd.appId())
737 .withPriority(fwd.priority())
738 .forDevice(deviceId)
739 .withSelector(filteredSelector)
740 .withTreatment(filteredTreatment)
741 .forTable(BRIDGING_TABLE);
742 if (fwd.permanent()) {
743 flowRuleBuilder.makePermanent();
744 } else {
745 flowRuleBuilder.makeTemporary(fwd.timeout());
746 }
747 rules.add(flowRuleBuilder.build());
748 return rules;
749 }
750
Saurav Das52025962016-01-28 22:30:01 -0800751 /*
752 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
753 * ACL table. Because we pop off vlan tags in TMAC table,
754 * we need to avoid matching on vlans in the ACL table.
755 */
756 @Override
757 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
758 log.info("Processing versatile forwarding objective");
759
Saurav Das52025962016-01-28 22:30:01 -0800760 if (fwd.nextId() == null && fwd.treatment() == null) {
761 log.error("Forwarding objective {} from {} must contain "
762 + "nextId or Treatment", fwd.selector(), fwd.appId());
763 return Collections.emptySet();
764 }
765
766 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
767 fwd.selector().criteria().forEach(criterion -> {
768 if (criterion instanceof VlanIdCriterion) {
769 // avoid matching on vlans
770 return;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800771 } else if (criterion instanceof Icmpv6TypeCriterion ||
772 criterion instanceof Icmpv6CodeCriterion) {
773 /*
774 * We silenty discard these criterions, our current
775 * OFDPA platform does not support these matches on
776 * the ACL table.
777 */
778 log.warn("ICMPv6 Type and ICMPv6 Code are not supported");
Saurav Das52025962016-01-28 22:30:01 -0800779 } else {
780 sbuilder.add(criterion);
781 }
782 });
783
784 // XXX driver does not currently do type checking as per Tables 65-67 in
785 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
786 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
787 if (fwd.treatment() != null) {
788 for (Instruction ins : fwd.treatment().allInstructions()) {
789 if (ins instanceof OutputInstruction) {
790 OutputInstruction o = (OutputInstruction) ins;
791 if (o.port() == PortNumber.CONTROLLER) {
Charles Chan0f43e472017-02-14 14:00:16 -0800792 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -0800793 } else {
794 log.warn("Only allowed treatments in versatile forwarding "
795 + "objectives are punts to the controller");
796 }
Charles Chan3fe71712018-06-15 18:54:18 -0700797 } else if (ins instanceof NoActionInstruction) {
798 // No action is allowed and nothing needs to be done
Saurav Das52025962016-01-28 22:30:01 -0800799 } else {
800 log.warn("Cannot process instruction in versatile fwd {}", ins);
801 }
802 }
Charles Chan2df0e8a2017-01-09 11:45:08 -0800803 if (fwd.treatment().clearedDeferred()) {
804 ttBuilder.wipeDeferred();
805 }
Saurav Das52025962016-01-28 22:30:01 -0800806 }
807 if (fwd.nextId() != null) {
808 // overide case
809 NextGroup next = getGroupForNextObjective(fwd.nextId());
810 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
811 // we only need the top level group's key to point the flow to it
812 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
813 if (group == null) {
814 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
815 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
816 fail(fwd, ObjectiveError.GROUPMISSING);
817 return Collections.emptySet();
818 }
819 ttBuilder.deferred().group(group.id());
820 }
821
822 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
823 .fromApp(fwd.appId())
824 .withPriority(fwd.priority())
825 .forDevice(deviceId)
826 .withSelector(sbuilder.build())
827 .withTreatment(ttBuilder.build())
828 .makePermanent()
829 .forTable(ACL_TABLE);
830 return Collections.singletonList(ruleBuilder.build());
831 }
832
833 /*
834 * Cpqd emulation requires table-miss-entries in forwarding tables.
835 * Real OFDPA does not require these rules as they are put in by default.
836 *
837 * (non-Javadoc)
838 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
839 */
Saurav Das2857f382015-11-03 14:39:27 -0800840 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700841 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -0800842 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
843 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
844 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
845 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
846 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
847 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
848 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
849 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
850 initTableMiss(ACL_TABLE, -1, null);
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700851 linkDiscoveryPuntTableRules();
Charles Chan0f43e472017-02-14 14:00:16 -0800852
853 if (supportPuntGroup()) {
Charles Chan0f43e472017-02-14 14:00:16 -0800854 initPopVlanPuntGroup();
855 } else {
856 initTableMiss(PUNT_TABLE, -1,
857 DefaultTrafficTreatment.builder().popVlan().punt().build());
858 }
Saurav Das558afec2015-05-31 17:12:48 -0700859 }
860
Charles Chanf6ec1532017-02-08 16:10:40 -0800861 /**
862 * Install table-miss flow entry.
863 *
864 * If treatment exists, use it directly.
865 * Else if treatment does not exist but nextTable > 0, transit to next table.
866 * Else apply empty treatment.
867 *
868 * @param thisTable this table ID
869 * @param nextTable next table ID
870 * @param treatment traffic treatment to apply.
871 */
872 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -0700873 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -0800874 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -0700875
Charles Chanf6ec1532017-02-08 16:10:40 -0800876 if (treatment == null) {
877 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
878 if (nextTable > 0) {
879 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -0700880 }
Charles Chanf6ec1532017-02-08 16:10:40 -0800881 treatment = tBuilder.build();
882 }
Saurav Das558afec2015-05-31 17:12:48 -0700883
Charles Chanb7504392017-02-10 12:51:04 -0800884 FlowRule rule = DefaultFlowRule.builder()
885 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -0800886 .withSelector(selector)
887 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -0800888 .withPriority(LOWEST_PRIORITY)
889 .fromApp(driverId)
890 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -0800891 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -0800892 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -0800893
894 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
895 @Override
896 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800897 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800898 }
Saurav Das2857f382015-11-03 14:39:27 -0800899 @Override
900 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800901 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800902 }
903 }));
904 }
Charles Chan0f43e472017-02-14 14:00:16 -0800905
906 /**
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700907 * Install lldp/bbdp matching rules at table PUNT_TABLE
908 * that forward traffic to controller.
909 *
910 */
911 private void linkDiscoveryPuntTableRules() {
912 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
913 TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build();
914
915 TrafficSelector.Builder lldpSelector = DefaultTrafficSelector.builder();
916 lldpSelector.matchEthType(EthType.EtherType.LLDP.ethType().toShort());
917 FlowRule lldpRule = DefaultFlowRule.builder()
918 .forDevice(deviceId)
919 .withSelector(lldpSelector.build())
920 .withTreatment(treatment)
921 .withPriority(HIGHEST_PRIORITY)
922 .fromApp(driverId)
923 .makePermanent()
924 .forTable(PUNT_TABLE).build();
925 ops = ops.add(lldpRule);
926
927 TrafficSelector.Builder bbdpSelector = DefaultTrafficSelector.builder();
928 bbdpSelector.matchEthType(EthType.EtherType.BDDP.ethType().toShort());
929 FlowRule bbdpRule = DefaultFlowRule.builder()
930 .forDevice(deviceId)
931 .withSelector(bbdpSelector.build())
932 .withTreatment(treatment)
933 .withPriority(HIGHEST_PRIORITY)
934 .fromApp(driverId)
935 .makePermanent()
936 .forTable(PUNT_TABLE).build();
937 ops.add(bbdpRule);
938
939 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
940 @Override
941 public void onSuccess(FlowRuleOperations ops) {
942 log.info("Added lldp/bbdp rules for table {} on {}", PUNT_TABLE, deviceId);
943 }
944 @Override
945 public void onError(FlowRuleOperations ops) {
946 log.warn("Failed to initialize lldp/bbdp rules for table {} on {}", PUNT_TABLE, deviceId);
947 }
948 }));
949 }
950
951 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800952 * Builds a indirect group contains pop_vlan and punt actions.
953 * <p>
954 * Using group instead of immediate action to ensure that
955 * the copy of packet on the data plane is not affected by the pop vlan action.
956 */
957 private void initPopVlanPuntGroup() {
Yi Tsengef19de12017-04-24 11:33:05 -0700958 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -0800959 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
960 .popVlan().punt().build();
961 GroupBucket bucket =
962 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
963 GroupDescription groupDesc =
964 new DefaultGroupDescription(
965 deviceId,
966 GroupDescription.Type.INDIRECT,
967 new GroupBuckets(Collections.singletonList(bucket)),
968 groupKey,
969 POP_VLAN_PUNT_GROUP_ID,
970 driverId);
971 groupService.addGroup(groupDesc);
972
973 log.info("Initialized pop vlan punt group on {}", deviceId);
974 }
Yi Tsengef19de12017-04-24 11:33:05 -0700975
976 /**
977 * Generates group key for a static indirect group that pop vlan and punt to
978 * controller.
979 *
980 * @return the group key of the indirect table
981 */
982 private GroupKey popVlanPuntGroupKey() {
983 int hash = POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_BIT_MASK);
984 return new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(hash));
985 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700986
987 private class PopVlanPuntGroupChecker implements Runnable {
988 @Override
989 public void run() {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700990 try {
991 groupCheckerLock.lock();
992 // this can happen outside of the lock but I think it is safer
993 // to include it here.
994 Group group = groupService.getGroup(deviceId, popVlanPuntGroupKey());
995 if (group != null) {
996 log.debug("PopVlanPuntGroupChecker: Installing {} missing rules at punt table.",
997 flowRuleQueue.size());
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700998
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700999 // if we have pending flow rules install them
1000 if (flowRuleQueue.size() > 0) {
1001 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1002 // we should not care about the context here, it can only be add
1003 // since when removing the rules the group should be there already.
1004 flowRuleQueue.forEach(ops::add);
1005 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1006 @Override
1007 public void onSuccess(FlowRuleOperations ops) {
1008 log.debug("Applied {} pop vlan punt rules in device {}",
1009 ops.stages().get(0).size(), deviceId);
1010 }
1011
1012 @Override
1013 public void onError(FlowRuleOperations ops) {
1014 log.error("Failed to apply all pop vlan punt rules in dev {}", deviceId);
1015 }
1016 }));
1017 }
1018 // this signifies that the group is created and now
1019 // flow rules can be installed directly
1020 flowRuleQueue = null;
1021 // shutdown the group checker gracefully
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001022 groupChecker.shutdown();
1023 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -07001024 } finally {
1025 groupCheckerLock.unlock();
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001026 }
1027 }
1028 }
Saurav Das558afec2015-05-31 17:12:48 -07001029}