blob: de19330fc2ae7f1378f5417b502889ab1ec19ed1 [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
Charles Chan0f43e472017-02-14 14:00:16 -0800141 /**
Charles Chan40132b32017-01-22 00:19:37 -0800142 * Determines whether this pipeline support copy ttl instructions or not.
143 *
144 * @return true if copy ttl instructions are supported
145 */
146 protected boolean supportCopyTtl() {
147 return true;
148 }
149
Charles Chan0f43e472017-02-14 14:00:16 -0800150 /**
151 * Determines whether this pipeline support push mpls to vlan-tagged packets or not.
152 * <p>
153 * If not support, pop vlan before push entering unicast and mpls table.
154 * Side effect: HostService learns redundant hosts with same MAC but
155 * different VLAN. No known side effect on the network reachability.
156 *
157 * @return true if push mpls to vlan-tagged packets is supported
158 */
159 protected boolean supportTaggedMpls() {
160 return false;
161 }
162
163 /**
164 * Determines whether this pipeline support punt action in group bucket.
165 *
166 * @return true if punt action in group bucket is supported
167 */
168 protected boolean supportPuntGroup() {
169 return false;
170 }
171
Charles Chan425854b2016-04-11 15:32:12 -0700172 @Override
Charles Chan40132b32017-01-22 00:19:37 -0800173 protected void initDriverId() {
Charles Chan425854b2016-04-11 15:32:12 -0700174 driverId = coreService.registerApplication(
175 "org.onosproject.driver.CpqdOfdpa2Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -0800176 }
Charles Chan425854b2016-04-11 15:32:12 -0700177
Charles Chan40132b32017-01-22 00:19:37 -0800178 @Override
179 protected void initGroupHander(PipelinerContext context) {
180 groupHandler = new CpqdOfdpa2GroupHandler();
181 groupHandler.init(deviceId, context);
Charles Chan425854b2016-04-11 15:32:12 -0700182 }
183
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700184 @Override
185 public void init(DeviceId deviceId, PipelinerContext context) {
186
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700187 if (supportPuntGroup()) {
188 // create a new executor at each init and a new empty queue
189 groupChecker = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/driver",
190 "cpqd-ofdpa-%d", log));
191 flowRuleQueue = new ConcurrentLinkedQueue<>();
192 groupCheckerLock = new ReentrantLock();
193 groupChecker.scheduleAtFixedRate(new PopVlanPuntGroupChecker(), 20, 50, TimeUnit.MILLISECONDS);
194 super.init(deviceId, context);
195 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700196 }
Saurav Das4ce45962015-11-24 23:21:05 -0800197 /*
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700198 * Cpqd emulation does not require the non OF-standard rules for
199 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800200 *
201 * (non-Javadoc)
202 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
203 */
Saurav Das558afec2015-05-31 17:12:48 -0700204 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800205 protected List<List<FlowRule>> processVlanIdFilter(PortCriterion portCriterion,
pierb2f71142019-06-10 17:10:26 +0200206 VlanIdCriterion vidCriterion,
207 VlanId assignedVlan,
208 ApplicationId applicationId,
209 boolean install) {
Charles Chan79769232016-07-05 16:34:39 -0700210 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800211 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
212 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
213 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800214 treatment.transition(TMAC_TABLE);
215
Saurav Das2857f382015-11-03 14:39:27 -0800216 if (vidCriterion.vlanId() == VlanId.NONE) {
217 // untagged packets are assigned vlans
218 treatment.pushVlan().setVlanId(assignedVlan);
Pier3cc7e662018-03-07 11:42:50 +0100219 } else if (!vidCriterion.vlanId().equals(assignedVlan)) {
220 // Rewrite with assigned vlans
221 treatment.setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800222 }
Saurav Das2857f382015-11-03 14:39:27 -0800223
224 // ofdpa cannot match on ALL portnumber, so we need to use separate
225 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800226 List<PortNumber> portnums = new ArrayList<>();
Ray Milkey94542b02018-05-10 12:42:51 -0700227 if (portCriterion != null) {
228 if (portCriterion.port() == PortNumber.ALL) {
229 for (Port port : deviceService.getPorts(deviceId)) {
230 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
231 portnums.add(port.number());
232 }
Saurav Das2857f382015-11-03 14:39:27 -0800233 }
Ray Milkey94542b02018-05-10 12:42:51 -0700234 } else {
235 portnums.add(portCriterion.port());
Saurav Das2857f382015-11-03 14:39:27 -0800236 }
Saurav Das2857f382015-11-03 14:39:27 -0800237 }
Saurav Das4f980082015-11-05 13:39:15 -0800238
Saurav Das2857f382015-11-03 14:39:27 -0800239 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800240 // NOTE: Emulating OFDPA behavior by popping off internal assigned
241 // VLAN before sending to controller
242 if (supportPuntGroup() && vidCriterion.vlanId() == VlanId.NONE) {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700243 try {
244 groupCheckerLock.lock();
245 if (flowRuleQueue == null) {
246 // this means that the group has been created
247 // and that groupChecker has destroyed the queue
248 log.debug("Installing punt table rule for untagged port {} and vlan {}.",
249 pnum, assignedVlan);
250 rules.add(buildPuntTableRule(pnum, assignedVlan));
251 } else {
252 // The VLAN punt group may be held back due to device initial audit.
253 // In that case, we queue all punt table flow until the group has been created.
254 log.debug("popVlanPuntGroup not found in dev:{}, queueing this flow rule.", deviceId);
255 flowRuleQueue.add(buildPuntTableRule(pnum, assignedVlan));
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700256 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700257 } finally {
258 groupCheckerLock.unlock();
Charles Chan0f43e472017-02-14 14:00:16 -0800259 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700260 } else if (vidCriterion.vlanId() != VlanId.NONE) {
261 // for tagged ports just forward to the controller
262 log.debug("Installing punt rule for tagged port {} and vlan {}.", pnum, vidCriterion.vlanId());
263 rules.add(buildPuntTableRuleTagged(pnum, vidCriterion.vlanId()));
Charles Chan0f43e472017-02-14 14:00:16 -0800264 }
265
Saurav Das4f980082015-11-05 13:39:15 -0800266 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800267 selector.matchInPort(pnum);
268 FlowRule rule = DefaultFlowRule.builder()
269 .forDevice(deviceId)
270 .withSelector(selector.build())
271 .withTreatment(treatment.build())
272 .withPriority(DEFAULT_PRIORITY)
273 .fromApp(applicationId)
274 .makePermanent()
275 .forTable(VLAN_TABLE).build();
276 rules.add(rule);
277 }
Charles Chanf57a8252016-06-29 19:12:37 -0700278
Charles Chan206506b2018-03-02 16:43:28 -0800279 return ImmutableList.of(rules);
Saurav Das2857f382015-11-03 14:39:27 -0800280 }
281
Pier Ventree0ae7a32016-11-23 09:57:42 -0800282 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800283 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
284 * a group that pop vlan and punt.
285 *
286 * @param portNumber port number
287 * @param assignedVlan internally assigned vlan id
288 * @return punt table flow rule
289 */
290 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
291 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
292 .matchInPort(portNumber)
293 .matchVlanId(assignedVlan);
294 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
Yi Tsengfa394de2017-02-01 11:26:40 -0800295 .group(new GroupId(POP_VLAN_PUNT_GROUP_ID));
Charles Chan0f43e472017-02-14 14:00:16 -0800296
297 return DefaultFlowRule.builder()
298 .forDevice(deviceId)
299 .withSelector(sbuilder.build())
300 .withTreatment(tbuilder.build())
301 .withPriority(PacketPriority.CONTROL.priorityValue())
302 .fromApp(driverId)
303 .makePermanent()
304 .forTable(PUNT_TABLE).build();
305 }
306
307 /**
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700308 * Creates punt table entry that matches IN_PORT and VLAN_VID and forwards
309 * packet to controller tagged.
310 *
311 * @param portNumber port number
312 * @param packetVlan vlan tag of the packet
313 * @return punt table flow rule
314 */
315 private FlowRule buildPuntTableRuleTagged(PortNumber portNumber, VlanId packetVlan) {
316 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
317 .matchInPort(portNumber)
318 .matchVlanId(packetVlan);
319 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder().punt();
320
321 return DefaultFlowRule.builder()
322 .forDevice(deviceId)
323 .withSelector(sbuilder.build())
324 .withTreatment(tbuilder.build())
325 .withPriority(PacketPriority.CONTROL.priorityValue())
326 .fromApp(driverId)
327 .makePermanent()
328 .forTable(PUNT_TABLE).build();
329 }
330
331 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800332 * Builds a punt to the controller rule for the arp protocol.
Charles Chan0f43e472017-02-14 14:00:16 -0800333 * <p>
334 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
335 * pop VLAN before sending to controller disregarding whether
336 * it's an internally assigned VLAN or a natural VLAN.
337 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800338 *
339 * @param assignedVlan the internal assigned vlan id
340 * @param applicationId the application id
341 * @return the punt flow rule for the arp
342 */
343 private FlowRule buildArpPunt(VlanId assignedVlan, ApplicationId applicationId) {
344 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
345 .matchEthType(Ethernet.TYPE_ARP)
346 .matchVlanId(assignedVlan);
347 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
348 .popVlan()
349 .punt();
350
351 return DefaultFlowRule.builder()
352 .forDevice(deviceId)
353 .withSelector(sbuilder.build())
354 .withTreatment(tbuilder.build())
355 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
356 .fromApp(applicationId)
357 .makePermanent()
358 .forTable(ACL_TABLE).build();
359 }
360
361 /**
362 * Builds a punt to the controller rule for the icmp v6 messages.
Charles Chan0f43e472017-02-14 14:00:16 -0800363 * <p>
364 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
365 * pop VLAN before sending to controller disregarding whether
366 * it's an internally assigned VLAN or a natural VLAN.
367 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800368 *
369 * @param assignedVlan the internal assigned vlan id
370 * @param applicationId the application id
371 * @return the punt flow rule for the icmp v6 messages
372 */
373 private FlowRule buildIcmpV6Punt(VlanId assignedVlan, ApplicationId applicationId) {
374 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
375 .matchVlanId(assignedVlan)
376 .matchEthType(Ethernet.TYPE_IPV6)
377 .matchIPProtocol(PROTOCOL_ICMP6);
378 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
379 .popVlan()
380 .punt();
381
382 return DefaultFlowRule.builder()
383 .forDevice(deviceId)
384 .withSelector(sbuilder.build())
385 .withTreatment(tbuilder.build())
386 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
387 .fromApp(applicationId)
388 .makePermanent()
389 .forTable(ACL_TABLE).build();
390 }
391
Saurav Das4ce45962015-11-24 23:21:05 -0800392 /*
393 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
394 * Workaround requires popping off the VLAN tags in the TMAC table.
395 *
396 * (non-Javadoc)
397 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
398 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800399 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800400 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das4ce45962015-11-24 23:21:05 -0800401 EthCriterion ethCriterion,
402 VlanIdCriterion vidCriterion,
403 VlanId assignedVlan,
Charles Chand57552d2018-03-02 15:41:41 -0800404 MacAddress unicastMac,
Saurav Das4ce45962015-11-24 23:21:05 -0800405 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800406 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
407 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
408 return processEthDstOnlyFilter(ethCriterion, applicationId);
409 }
410
Charles Chan5b9df8d2016-03-28 22:21:40 -0700411 // Multicast MAC
412 if (ethCriterion.mask() != null) {
Charles Chand57552d2018-03-02 15:41:41 -0800413 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700414 }
415
Saurav Das4ce45962015-11-24 23:21:05 -0800416 //handling untagged packets via assigned VLAN
417 if (vidCriterion.vlanId() == VlanId.NONE) {
418 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
419 }
420 // ofdpa cannot match on ALL portnumber, so we need to use separate
421 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800422 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800423 if (portCriterion != null) {
424 if (portCriterion.port() == PortNumber.ALL) {
425 for (Port port : deviceService.getPorts(deviceId)) {
426 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
427 portnums.add(port.number());
428 }
Saurav Das4ce45962015-11-24 23:21:05 -0800429 }
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800430 } else {
431 portnums.add(portCriterion.port());
Saurav Das4ce45962015-11-24 23:21:05 -0800432 }
Saurav Das4ce45962015-11-24 23:21:05 -0800433 }
434
Charles Chan93090352018-03-02 13:26:22 -0800435 List<FlowRule> rules = new ArrayList<>();
Saurav Das4ce45962015-11-24 23:21:05 -0800436 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800437 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800438 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
439 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
440 selector.matchInPort(pnum);
441 selector.matchVlanId(vidCriterion.vlanId());
442 selector.matchEthType(Ethernet.TYPE_IPV4);
443 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800444 if (!supportTaggedMpls()) {
445 treatment.popVlan();
446 }
Saurav Das4ce45962015-11-24 23:21:05 -0800447 treatment.transition(UNICAST_ROUTING_TABLE);
448 FlowRule rule = DefaultFlowRule.builder()
449 .forDevice(deviceId)
450 .withSelector(selector.build())
451 .withTreatment(treatment.build())
452 .withPriority(DEFAULT_PRIORITY)
453 .fromApp(applicationId)
454 .makePermanent()
455 .forTable(TMAC_TABLE).build();
456 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800457
458 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800459 selector = DefaultTrafficSelector.builder();
460 treatment = DefaultTrafficTreatment.builder();
461 selector.matchInPort(pnum);
462 selector.matchVlanId(vidCriterion.vlanId());
463 selector.matchEthType(Ethernet.MPLS_UNICAST);
464 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800465 if (!supportTaggedMpls()) {
466 treatment.popVlan();
467 }
Saurav Das4ce45962015-11-24 23:21:05 -0800468 treatment.transition(MPLS_TABLE_0);
469 rule = DefaultFlowRule.builder()
470 .forDevice(deviceId)
471 .withSelector(selector.build())
472 .withTreatment(treatment.build())
473 .withPriority(DEFAULT_PRIORITY)
474 .fromApp(applicationId)
475 .makePermanent()
476 .forTable(TMAC_TABLE).build();
477 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800478
479 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800480 selector = DefaultTrafficSelector.builder();
481 treatment = DefaultTrafficTreatment.builder();
482 selector.matchInPort(pnum);
483 selector.matchVlanId(vidCriterion.vlanId());
484 selector.matchEthType(Ethernet.TYPE_IPV6);
485 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800486 if (!supportTaggedMpls()) {
487 treatment.popVlan();
488 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800489 treatment.transition(UNICAST_ROUTING_TABLE);
490 rule = DefaultFlowRule.builder()
491 .forDevice(deviceId)
492 .withSelector(selector.build())
493 .withTreatment(treatment.build())
494 .withPriority(DEFAULT_PRIORITY)
495 .fromApp(applicationId)
496 .makePermanent()
497 .forTable(TMAC_TABLE).build();
498 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800499 }
Charles Chan206506b2018-03-02 16:43:28 -0800500 return ImmutableList.of(rules);
Saurav Das4ce45962015-11-24 23:21:05 -0800501 }
502
Charles Chan5270ed02016-01-30 23:22:37 -0800503 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800504 protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700505 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800506 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
507 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
508 selector.matchEthType(Ethernet.TYPE_IPV4);
509 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800510 if (!supportTaggedMpls()) {
511 treatment.popVlan();
512 }
Charles Chan5270ed02016-01-30 23:22:37 -0800513 treatment.transition(UNICAST_ROUTING_TABLE);
514 FlowRule rule = DefaultFlowRule.builder()
515 .forDevice(deviceId)
516 .withSelector(selector.build())
517 .withTreatment(treatment.build())
518 .withPriority(DEFAULT_PRIORITY)
519 .fromApp(applicationId)
520 .makePermanent()
521 .forTable(TMAC_TABLE).build();
Charles Chan206506b2018-03-02 16:43:28 -0800522 return ImmutableList.of(ImmutableList.of(rule));
Charles Chan5270ed02016-01-30 23:22:37 -0800523 }
524
Saurav Das4ce45962015-11-24 23:21:05 -0800525 /*
526 * Cpqd emulation allows MPLS ecmp.
527 *
528 * (non-Javadoc)
529 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
530 */
531 @Override
532 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800533 TrafficSelector selector = fwd.selector();
534 EthTypeCriterion ethType =
535 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
536 if ((ethType == null) ||
537 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800538 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
539 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800540 log.warn("processSpecific: Unsupported forwarding objective criteria"
541 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800542 fail(fwd, ObjectiveError.UNSUPPORTED);
543 return Collections.emptySet();
544 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800545 boolean defaultRule = false;
Charles Chan93090352018-03-02 13:26:22 -0800546 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800547 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800548 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
549
Saurav Das8a0732e2015-11-20 15:27:53 -0800550 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800551 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700552 if (ipv4Dst.isMulticast()) {
553 if (ipv4Dst.prefixLength() != 32) {
554 log.warn("Multicast specific forwarding objective can only be /32");
555 fail(fwd, ObjectiveError.BADPARAMS);
556 return ImmutableSet.of();
557 }
558 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
559 if (assignedVlan == null) {
560 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
561 fail(fwd, ObjectiveError.BADPARAMS);
562 return ImmutableSet.of();
563 }
564 filteredSelector.matchVlanId(assignedVlan);
565 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
566 forTableId = MULTICAST_ROUTING_TABLE;
567 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
568 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800569 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700570 if (ipv4Dst.prefixLength() == 0) {
571 // The entire IPV4_DST field is wildcarded intentionally
572 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700573 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700574 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700575 }
576 forTableId = UNICAST_ROUTING_TABLE;
577 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
578 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800579 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800580 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
Julia Ferguson65428c32017-08-10 18:15:24 +0000581 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
582 if (ipv6Dst.isMulticast()) {
583 if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
584 log.debug("Multicast specific IPv6 forwarding objective can only be /128");
585 fail(fwd, ObjectiveError.BADPARAMS);
586 return ImmutableSet.of();
587 }
588 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
589 if (assignedVlan == null) {
590 log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
591 fail(fwd, ObjectiveError.BADPARAMS);
592 return ImmutableSet.of();
593 }
594 filteredSelector.matchVlanId(assignedVlan);
595 filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
596 forTableId = MULTICAST_ROUTING_TABLE;
597 log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
598 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
599 } else {
600 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
601 return Collections.emptyList();
602 }
603 forTableId = UNICAST_ROUTING_TABLE;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800604 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800605 } else {
606 filteredSelector
607 .matchEthType(Ethernet.MPLS_UNICAST)
608 .matchMplsLabel(((MplsCriterion)
609 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
610 MplsBosCriterion bos = (MplsBosCriterion) selector
611 .getCriterion(Criterion.Type.MPLS_BOS);
612 if (bos != null) {
613 filteredSelector.matchMplsBos(bos.mplsBos());
614 }
615 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800616 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
617 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800618 }
619
620 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
621 if (fwd.treatment() != null) {
622 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan40132b32017-01-22 00:19:37 -0800623 if (!supportCopyTtl() && i instanceof L3ModificationInstruction) {
624 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
625 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
626 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
627 continue;
628 }
629 }
Charles Chan7d10b162015-12-07 18:54:45 -0800630 /*
631 * NOTE: OF-DPA does not support immediate instruction in
632 * L3 unicast and MPLS table.
633 */
634 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800635 }
636 }
637
638 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800639 NextGroup next = getGroupForNextObjective(fwd.nextId());
640 if (next != null) {
641 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
642 // we only need the top level group's key to point the flow to it
643 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
644 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700645 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
646 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800647 fail(fwd, ObjectiveError.GROUPMISSING);
648 return Collections.emptySet();
649 }
650 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800651 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800652 }
653 tb.transition(ACL_TABLE);
654 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
655 .fromApp(fwd.appId())
656 .withPriority(fwd.priority())
657 .forDevice(deviceId)
658 .withSelector(filteredSelector.build())
659 .withTreatment(tb.build())
660 .forTable(forTableId);
661
662 if (fwd.permanent()) {
663 ruleBuilder.makePermanent();
664 } else {
665 ruleBuilder.makeTemporary(fwd.timeout());
666 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800667 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
668 flowRuleCollection.add(ruleBuilder.build());
669 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800670 flowRuleCollection.add(
671 defaultRoute(fwd, complementarySelector, forTableId, tb)
672 );
Flavio Castroe10fa242016-01-15 12:43:51 -0800673 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
674 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800675 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800676 }
677
Charles Chan1e492d32016-01-30 23:22:37 -0800678 @Override
679 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
680 List<FlowRule> rules = new ArrayList<>();
681
682 // Build filtered selector
683 TrafficSelector selector = fwd.selector();
684 EthCriterion ethCriterion = (EthCriterion) selector
685 .getCriterion(Criterion.Type.ETH_DST);
686 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
687 .getCriterion(Criterion.Type.VLAN_VID);
688
689 if (vlanIdCriterion == null) {
690 log.warn("Forwarding objective for bridging requires vlan. Not "
691 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
692 fail(fwd, ObjectiveError.BADPARAMS);
693 return Collections.emptySet();
694 }
695
696 TrafficSelector.Builder filteredSelectorBuilder =
697 DefaultTrafficSelector.builder();
698 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -0800699 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -0800700 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
701 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
702 fwd.id(), fwd.nextId(), deviceId);
703 } else {
704 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
705 + "in dev:{} for vlan:{}",
706 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
707 }
708 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
709 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
710
711 if (fwd.treatment() != null) {
712 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
713 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
714 }
715
716 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
717 if (fwd.nextId() != null) {
718 NextGroup next = getGroupForNextObjective(fwd.nextId());
719 if (next != null) {
720 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
721 // we only need the top level group's key to point the flow to it
722 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
723 if (group != null) {
724 treatmentBuilder.deferred().group(group.id());
725 } else {
726 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
727 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
728 fail(fwd, ObjectiveError.GROUPMISSING);
729 return Collections.emptySet();
730 }
731 }
732 }
733 treatmentBuilder.immediate().transition(ACL_TABLE);
734 TrafficTreatment filteredTreatment = treatmentBuilder.build();
735
736 // Build bridging table entries
737 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
738 flowRuleBuilder.fromApp(fwd.appId())
739 .withPriority(fwd.priority())
740 .forDevice(deviceId)
741 .withSelector(filteredSelector)
742 .withTreatment(filteredTreatment)
743 .forTable(BRIDGING_TABLE);
744 if (fwd.permanent()) {
745 flowRuleBuilder.makePermanent();
746 } else {
747 flowRuleBuilder.makeTemporary(fwd.timeout());
748 }
749 rules.add(flowRuleBuilder.build());
750 return rules;
751 }
752
Saurav Das52025962016-01-28 22:30:01 -0800753 /*
754 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
755 * ACL table. Because we pop off vlan tags in TMAC table,
756 * we need to avoid matching on vlans in the ACL table.
757 */
758 @Override
759 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
760 log.info("Processing versatile forwarding objective");
761
Saurav Das52025962016-01-28 22:30:01 -0800762 if (fwd.nextId() == null && fwd.treatment() == null) {
763 log.error("Forwarding objective {} from {} must contain "
764 + "nextId or Treatment", fwd.selector(), fwd.appId());
765 return Collections.emptySet();
766 }
767
768 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
769 fwd.selector().criteria().forEach(criterion -> {
770 if (criterion instanceof VlanIdCriterion) {
771 // avoid matching on vlans
772 return;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800773 } else if (criterion instanceof Icmpv6TypeCriterion ||
774 criterion instanceof Icmpv6CodeCriterion) {
775 /*
776 * We silenty discard these criterions, our current
777 * OFDPA platform does not support these matches on
778 * the ACL table.
779 */
780 log.warn("ICMPv6 Type and ICMPv6 Code are not supported");
Saurav Das52025962016-01-28 22:30:01 -0800781 } else {
782 sbuilder.add(criterion);
783 }
784 });
785
786 // XXX driver does not currently do type checking as per Tables 65-67 in
787 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
788 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
789 if (fwd.treatment() != null) {
790 for (Instruction ins : fwd.treatment().allInstructions()) {
791 if (ins instanceof OutputInstruction) {
792 OutputInstruction o = (OutputInstruction) ins;
793 if (o.port() == PortNumber.CONTROLLER) {
Charles Chan0f43e472017-02-14 14:00:16 -0800794 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -0800795 } else {
796 log.warn("Only allowed treatments in versatile forwarding "
797 + "objectives are punts to the controller");
798 }
Charles Chan3fe71712018-06-15 18:54:18 -0700799 } else if (ins instanceof NoActionInstruction) {
800 // No action is allowed and nothing needs to be done
Saurav Das52025962016-01-28 22:30:01 -0800801 } else {
802 log.warn("Cannot process instruction in versatile fwd {}", ins);
803 }
804 }
Charles Chan2df0e8a2017-01-09 11:45:08 -0800805 if (fwd.treatment().clearedDeferred()) {
806 ttBuilder.wipeDeferred();
807 }
Saurav Das52025962016-01-28 22:30:01 -0800808 }
809 if (fwd.nextId() != null) {
810 // overide case
811 NextGroup next = getGroupForNextObjective(fwd.nextId());
812 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
813 // we only need the top level group's key to point the flow to it
814 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
815 if (group == null) {
816 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
817 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
818 fail(fwd, ObjectiveError.GROUPMISSING);
819 return Collections.emptySet();
820 }
821 ttBuilder.deferred().group(group.id());
822 }
823
824 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
825 .fromApp(fwd.appId())
826 .withPriority(fwd.priority())
827 .forDevice(deviceId)
828 .withSelector(sbuilder.build())
829 .withTreatment(ttBuilder.build())
830 .makePermanent()
831 .forTable(ACL_TABLE);
832 return Collections.singletonList(ruleBuilder.build());
833 }
834
835 /*
836 * Cpqd emulation requires table-miss-entries in forwarding tables.
837 * Real OFDPA does not require these rules as they are put in by default.
838 *
839 * (non-Javadoc)
840 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
841 */
Saurav Das2857f382015-11-03 14:39:27 -0800842 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700843 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -0800844 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
845 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
846 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
847 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
848 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
849 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
850 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
851 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
852 initTableMiss(ACL_TABLE, -1, null);
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700853 linkDiscoveryPuntTableRules();
Charles Chan0f43e472017-02-14 14:00:16 -0800854
855 if (supportPuntGroup()) {
Charles Chan0f43e472017-02-14 14:00:16 -0800856 initPopVlanPuntGroup();
857 } else {
858 initTableMiss(PUNT_TABLE, -1,
859 DefaultTrafficTreatment.builder().popVlan().punt().build());
860 }
Saurav Das558afec2015-05-31 17:12:48 -0700861 }
862
Charles Chanf6ec1532017-02-08 16:10:40 -0800863 /**
864 * Install table-miss flow entry.
865 *
866 * If treatment exists, use it directly.
867 * Else if treatment does not exist but nextTable > 0, transit to next table.
868 * Else apply empty treatment.
869 *
870 * @param thisTable this table ID
871 * @param nextTable next table ID
872 * @param treatment traffic treatment to apply.
873 */
874 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -0700875 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -0800876 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -0700877
Charles Chanf6ec1532017-02-08 16:10:40 -0800878 if (treatment == null) {
879 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
880 if (nextTable > 0) {
881 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -0700882 }
Charles Chanf6ec1532017-02-08 16:10:40 -0800883 treatment = tBuilder.build();
884 }
Saurav Das558afec2015-05-31 17:12:48 -0700885
Charles Chanb7504392017-02-10 12:51:04 -0800886 FlowRule rule = DefaultFlowRule.builder()
887 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -0800888 .withSelector(selector)
889 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -0800890 .withPriority(LOWEST_PRIORITY)
891 .fromApp(driverId)
892 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -0800893 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -0800894 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -0800895
896 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
897 @Override
898 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800899 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800900 }
Saurav Das2857f382015-11-03 14:39:27 -0800901 @Override
902 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800903 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800904 }
905 }));
906 }
Charles Chan0f43e472017-02-14 14:00:16 -0800907
908 /**
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700909 * Install lldp/bbdp matching rules at table PUNT_TABLE
910 * that forward traffic to controller.
911 *
912 */
913 private void linkDiscoveryPuntTableRules() {
914 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
915 TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build();
916
917 TrafficSelector.Builder lldpSelector = DefaultTrafficSelector.builder();
918 lldpSelector.matchEthType(EthType.EtherType.LLDP.ethType().toShort());
919 FlowRule lldpRule = DefaultFlowRule.builder()
920 .forDevice(deviceId)
921 .withSelector(lldpSelector.build())
922 .withTreatment(treatment)
923 .withPriority(HIGHEST_PRIORITY)
924 .fromApp(driverId)
925 .makePermanent()
926 .forTable(PUNT_TABLE).build();
927 ops = ops.add(lldpRule);
928
929 TrafficSelector.Builder bbdpSelector = DefaultTrafficSelector.builder();
930 bbdpSelector.matchEthType(EthType.EtherType.BDDP.ethType().toShort());
931 FlowRule bbdpRule = DefaultFlowRule.builder()
932 .forDevice(deviceId)
933 .withSelector(bbdpSelector.build())
934 .withTreatment(treatment)
935 .withPriority(HIGHEST_PRIORITY)
936 .fromApp(driverId)
937 .makePermanent()
938 .forTable(PUNT_TABLE).build();
939 ops.add(bbdpRule);
940
941 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
942 @Override
943 public void onSuccess(FlowRuleOperations ops) {
944 log.info("Added lldp/bbdp rules for table {} on {}", PUNT_TABLE, deviceId);
945 }
946 @Override
947 public void onError(FlowRuleOperations ops) {
948 log.warn("Failed to initialize lldp/bbdp rules for table {} on {}", PUNT_TABLE, deviceId);
949 }
950 }));
951 }
952
953 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800954 * Builds a indirect group contains pop_vlan and punt actions.
955 * <p>
956 * Using group instead of immediate action to ensure that
957 * the copy of packet on the data plane is not affected by the pop vlan action.
958 */
959 private void initPopVlanPuntGroup() {
Yi Tsengef19de12017-04-24 11:33:05 -0700960 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -0800961 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
962 .popVlan().punt().build();
963 GroupBucket bucket =
964 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
965 GroupDescription groupDesc =
966 new DefaultGroupDescription(
967 deviceId,
968 GroupDescription.Type.INDIRECT,
969 new GroupBuckets(Collections.singletonList(bucket)),
970 groupKey,
971 POP_VLAN_PUNT_GROUP_ID,
972 driverId);
973 groupService.addGroup(groupDesc);
974
975 log.info("Initialized pop vlan punt group on {}", deviceId);
976 }
Yi Tsengef19de12017-04-24 11:33:05 -0700977
978 /**
979 * Generates group key for a static indirect group that pop vlan and punt to
980 * controller.
981 *
982 * @return the group key of the indirect table
983 */
984 private GroupKey popVlanPuntGroupKey() {
985 int hash = POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_BIT_MASK);
986 return new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(hash));
987 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700988
989 private class PopVlanPuntGroupChecker implements Runnable {
990 @Override
991 public void run() {
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -0700992 try {
993 groupCheckerLock.lock();
994 // this can happen outside of the lock but I think it is safer
995 // to include it here.
996 Group group = groupService.getGroup(deviceId, popVlanPuntGroupKey());
997 if (group != null) {
998 log.debug("PopVlanPuntGroupChecker: Installing {} missing rules at punt table.",
999 flowRuleQueue.size());
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001000
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -07001001 // if we have pending flow rules install them
1002 if (flowRuleQueue.size() > 0) {
1003 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1004 // we should not care about the context here, it can only be add
1005 // since when removing the rules the group should be there already.
1006 flowRuleQueue.forEach(ops::add);
1007 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1008 @Override
1009 public void onSuccess(FlowRuleOperations ops) {
1010 log.debug("Applied {} pop vlan punt rules in device {}",
1011 ops.stages().get(0).size(), deviceId);
1012 }
1013
1014 @Override
1015 public void onError(FlowRuleOperations ops) {
1016 log.error("Failed to apply all pop vlan punt rules in dev {}", deviceId);
1017 }
1018 }));
1019 }
1020 // this signifies that the group is created and now
1021 // flow rules can be installed directly
1022 flowRuleQueue = null;
1023 // shutdown the group checker gracefully
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001024 groupChecker.shutdown();
1025 }
Andreas Pantelopoulosc78c1f52018-06-04 15:10:35 -07001026 } finally {
1027 groupCheckerLock.unlock();
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -07001028 }
1029 }
1030 }
Saurav Das558afec2015-05-31 17:12:48 -07001031}