blob: 45ca7bb1dc272decdfc249aebab724f1de70ac35 [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;
Saurav Das8a0732e2015-11-20 15:27:53 -080020import org.onlab.packet.Ethernet;
Julia Ferguson65428c32017-08-10 18:15:24 +000021import org.onlab.packet.IpAddress;
Flavio Castroe10fa242016-01-15 12:43:51 -080022import org.onlab.packet.IpPrefix;
Charles Chand57552d2018-03-02 15:41:41 -080023import org.onlab.packet.MacAddress;
Saurav Das2857f382015-11-03 14:39:27 -080024import org.onlab.packet.VlanId;
25import org.onosproject.core.ApplicationId;
Yi Tsengfa394de2017-02-01 11:26:40 -080026import org.onosproject.core.GroupId;
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -070027import org.onosproject.net.DeviceId;
Saurav Das2857f382015-11-03 14:39:27 -080028import org.onosproject.net.Port;
29import org.onosproject.net.PortNumber;
Saurav Das8a0732e2015-11-20 15:27:53 -080030import org.onosproject.net.behaviour.NextGroup;
Charles Chan425854b2016-04-11 15:32:12 -070031import org.onosproject.net.behaviour.PipelinerContext;
Saurav Das558afec2015-05-31 17:12:48 -070032import org.onosproject.net.flow.DefaultFlowRule;
33import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.FlowRule;
36import org.onosproject.net.flow.FlowRuleOperations;
37import org.onosproject.net.flow.FlowRuleOperationsContext;
38import org.onosproject.net.flow.TrafficSelector;
39import org.onosproject.net.flow.TrafficTreatment;
Saurav Das4ce45962015-11-24 23:21:05 -080040import org.onosproject.net.flow.criteria.Criteria;
Saurav Das8a0732e2015-11-20 15:27:53 -080041import org.onosproject.net.flow.criteria.Criterion;
Saurav Das4ce45962015-11-24 23:21:05 -080042import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080043import org.onosproject.net.flow.criteria.EthTypeCriterion;
44import org.onosproject.net.flow.criteria.IPCriterion;
Pier Ventree0ae7a32016-11-23 09:57:42 -080045import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion;
46import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080047import org.onosproject.net.flow.criteria.MplsBosCriterion;
48import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das2857f382015-11-03 14:39:27 -080049import org.onosproject.net.flow.criteria.PortCriterion;
50import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080051import org.onosproject.net.flow.instructions.Instruction;
Saurav Das52025962016-01-28 22:30:01 -080052import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Charles Chan40132b32017-01-22 00:19:37 -080053import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Saurav Das8a0732e2015-11-20 15:27:53 -080054import org.onosproject.net.flowobjective.ForwardingObjective;
55import org.onosproject.net.flowobjective.ObjectiveError;
Charles Chan0f43e472017-02-14 14:00:16 -080056import org.onosproject.net.group.DefaultGroupBucket;
57import org.onosproject.net.group.DefaultGroupDescription;
58import org.onosproject.net.group.DefaultGroupKey;
Saurav Das8a0732e2015-11-20 15:27:53 -080059import org.onosproject.net.group.Group;
Charles Chan0f43e472017-02-14 14:00:16 -080060import org.onosproject.net.group.GroupBucket;
61import org.onosproject.net.group.GroupBuckets;
62import org.onosproject.net.group.GroupDescription;
Saurav Das8a0732e2015-11-20 15:27:53 -080063import org.onosproject.net.group.GroupKey;
Charles Chanf57a8252016-06-29 19:12:37 -070064import org.onosproject.net.packet.PacketPriority;
Saurav Das558afec2015-05-31 17:12:48 -070065import org.slf4j.Logger;
66
Jonathan Hart855179c2016-04-26 07:40:04 -070067import java.util.ArrayList;
68import java.util.Collection;
69import java.util.Collections;
70import java.util.Deque;
71import java.util.List;
Charles Chan0f43e472017-02-14 14:00:16 -080072import java.util.Objects;
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -070073import java.util.Queue;
74import java.util.concurrent.ConcurrentLinkedQueue;
75import java.util.concurrent.Executors;
76import java.util.concurrent.ScheduledExecutorService;
77import java.util.concurrent.TimeUnit;
Jonathan Hart855179c2016-04-26 07:40:04 -070078
Pier Ventree0ae7a32016-11-23 09:57:42 -080079import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Charles Chand05f54b2017-02-13 11:56:54 -080080import static org.onlab.packet.MacAddress.BROADCAST;
81import static org.onlab.packet.MacAddress.NONE;
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -070082import static org.onlab.util.Tools.groupedThreads;
Yi Tsengef19de12017-04-24 11:33:05 -070083import static org.onosproject.driver.pipeline.ofdpa.OfdpaGroupHandlerUtility.*;
Jonathan Hart855179c2016-04-26 07:40:04 -070084import static org.slf4j.LoggerFactory.getLogger;
85
Saurav Das558afec2015-05-31 17:12:48 -070086
87/**
Charles Chan40132b32017-01-22 00:19:37 -080088 * Driver for software switch emulation of the OFDPA pipeline.
Saurav Das52025962016-01-28 22:30:01 -080089 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
90 * does not handle vlan tags and mpls labels simultaneously, which requires us
91 * to do some workarounds in the driver. This driver is meant for the use of
92 * the cpqd switch when MPLS is required. As a result this driver works only
93 * on incoming untagged packets.
Saurav Das558afec2015-05-31 17:12:48 -070094 */
Charles Chan361154b2016-03-24 10:23:39 -070095public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -070096
97 private final Logger log = getLogger(getClass());
98
Charles Chan40132b32017-01-22 00:19:37 -080099 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800100 * Table that determines whether VLAN is popped before punting to controller.
101 * <p>
102 * This is a non-OFDPA table to emulate OFDPA packet in behavior.
103 * VLAN will be popped before punting if the VLAN is internally assigned.
104 * <p>
105 * Also note that 63 is the max table number in CpqD.
106 */
107 private static final int PUNT_TABLE = 63;
108
109 /**
110 * A static indirect group that pop vlan and punt to controller.
111 * <p>
112 * The purpose of using a group instead of immediate action is that this
113 * won't affect another copy on the data plane when write action exists.
114 */
115 private static final int POP_VLAN_PUNT_GROUP_ID = 0xc0000000;
116
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700117 /**
118 * Executor for group checker thread that checks pop vlan punt group.
119 */
120 private ScheduledExecutorService groupChecker;
121
122 /**
123 * Queue for passing pop vlan punt group flow rules to the GroupChecker thread.
124 */
125 private Queue<FlowRule> flowRuleQueue = new ConcurrentLinkedQueue<>();
126
Charles Chan053b1cb2017-03-22 16:56:35 -0700127 @Override
128 protected boolean requireVlanExtensions() {
129 return false;
130 }
131
Charles Chan0f43e472017-02-14 14:00:16 -0800132 /**
Charles Chan40132b32017-01-22 00:19:37 -0800133 * Determines whether this pipeline support copy ttl instructions or not.
134 *
135 * @return true if copy ttl instructions are supported
136 */
137 protected boolean supportCopyTtl() {
138 return true;
139 }
140
Charles Chan0f43e472017-02-14 14:00:16 -0800141 /**
142 * Determines whether this pipeline support push mpls to vlan-tagged packets or not.
143 * <p>
144 * If not support, pop vlan before push entering unicast and mpls table.
145 * Side effect: HostService learns redundant hosts with same MAC but
146 * different VLAN. No known side effect on the network reachability.
147 *
148 * @return true if push mpls to vlan-tagged packets is supported
149 */
150 protected boolean supportTaggedMpls() {
151 return false;
152 }
153
154 /**
155 * Determines whether this pipeline support punt action in group bucket.
156 *
157 * @return true if punt action in group bucket is supported
158 */
159 protected boolean supportPuntGroup() {
160 return false;
161 }
162
Charles Chan425854b2016-04-11 15:32:12 -0700163 @Override
Charles Chan40132b32017-01-22 00:19:37 -0800164 protected void initDriverId() {
Charles Chan425854b2016-04-11 15:32:12 -0700165 driverId = coreService.registerApplication(
166 "org.onosproject.driver.CpqdOfdpa2Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -0800167 }
Charles Chan425854b2016-04-11 15:32:12 -0700168
Charles Chan40132b32017-01-22 00:19:37 -0800169 @Override
170 protected void initGroupHander(PipelinerContext context) {
171 groupHandler = new CpqdOfdpa2GroupHandler();
172 groupHandler.init(deviceId, context);
Charles Chan425854b2016-04-11 15:32:12 -0700173 }
174
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700175 @Override
176 public void init(DeviceId deviceId, PipelinerContext context) {
177
178 // create a new executor at each init
179 groupChecker = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/driver",
180 "cpqd-ofdpa-%d", log));
181 groupChecker.scheduleAtFixedRate(new PopVlanPuntGroupChecker(), 100, 300, TimeUnit.MILLISECONDS);
182 super.init(deviceId, context);
183 }
Saurav Das4ce45962015-11-24 23:21:05 -0800184 /*
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700185 * Cpqd emulation does not require the non OF-standard rules for
186 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800187 *
188 * (non-Javadoc)
189 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
190 */
Saurav Das558afec2015-05-31 17:12:48 -0700191 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800192 protected List<List<FlowRule>> processVlanIdFilter(PortCriterion portCriterion,
Saurav Das2857f382015-11-03 14:39:27 -0800193 VlanIdCriterion vidCriterion,
194 VlanId assignedVlan,
195 ApplicationId applicationId) {
Charles Chan79769232016-07-05 16:34:39 -0700196 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800197 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
198 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
199 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800200 treatment.transition(TMAC_TABLE);
201
Saurav Das2857f382015-11-03 14:39:27 -0800202 if (vidCriterion.vlanId() == VlanId.NONE) {
203 // untagged packets are assigned vlans
204 treatment.pushVlan().setVlanId(assignedVlan);
Pier3cc7e662018-03-07 11:42:50 +0100205 } else if (!vidCriterion.vlanId().equals(assignedVlan)) {
206 // Rewrite with assigned vlans
207 treatment.setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800208 }
Saurav Das2857f382015-11-03 14:39:27 -0800209
210 // ofdpa cannot match on ALL portnumber, so we need to use separate
211 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800212 List<PortNumber> portnums = new ArrayList<>();
Ray Milkey94542b02018-05-10 12:42:51 -0700213 if (portCriterion != null) {
214 if (portCriterion.port() == PortNumber.ALL) {
215 for (Port port : deviceService.getPorts(deviceId)) {
216 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
217 portnums.add(port.number());
218 }
Saurav Das2857f382015-11-03 14:39:27 -0800219 }
Ray Milkey94542b02018-05-10 12:42:51 -0700220 } else {
221 portnums.add(portCriterion.port());
Saurav Das2857f382015-11-03 14:39:27 -0800222 }
Saurav Das2857f382015-11-03 14:39:27 -0800223 }
Saurav Das4f980082015-11-05 13:39:15 -0800224
Saurav Das2857f382015-11-03 14:39:27 -0800225 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800226 // NOTE: Emulating OFDPA behavior by popping off internal assigned
227 // VLAN before sending to controller
228 if (supportPuntGroup() && vidCriterion.vlanId() == VlanId.NONE) {
Yi Tsengef19de12017-04-24 11:33:05 -0700229 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -0800230 Group group = groupService.getGroup(deviceId, groupKey);
231 if (group != null) {
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700232 if (!groupChecker.isShutdown()) {
233 groupChecker.shutdown();
234 }
Charles Chan0f43e472017-02-14 14:00:16 -0800235 rules.add(buildPuntTableRule(pnum, assignedVlan));
236 } else {
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700237 // The VLAN punt group may be held back due to device initial audit.
238 // In that case, we queue all punt table flow until the group has been created.
239 log.info("popVlanPuntGroup not found in dev:{}, queueing this flow rule.", deviceId);
240 flowRuleQueue.add(buildPuntTableRule(pnum, assignedVlan));
Charles Chan0f43e472017-02-14 14:00:16 -0800241 }
242 }
243
Saurav Das4f980082015-11-05 13:39:15 -0800244 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800245 selector.matchInPort(pnum);
246 FlowRule rule = DefaultFlowRule.builder()
247 .forDevice(deviceId)
248 .withSelector(selector.build())
249 .withTreatment(treatment.build())
250 .withPriority(DEFAULT_PRIORITY)
251 .fromApp(applicationId)
252 .makePermanent()
253 .forTable(VLAN_TABLE).build();
254 rules.add(rule);
255 }
Charles Chanf57a8252016-06-29 19:12:37 -0700256
Charles Chan206506b2018-03-02 16:43:28 -0800257 return ImmutableList.of(rules);
Saurav Das2857f382015-11-03 14:39:27 -0800258 }
259
Pier Ventree0ae7a32016-11-23 09:57:42 -0800260 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800261 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
262 * a group that pop vlan and punt.
263 *
264 * @param portNumber port number
265 * @param assignedVlan internally assigned vlan id
266 * @return punt table flow rule
267 */
268 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
269 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
270 .matchInPort(portNumber)
271 .matchVlanId(assignedVlan);
272 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
Yi Tsengfa394de2017-02-01 11:26:40 -0800273 .group(new GroupId(POP_VLAN_PUNT_GROUP_ID));
Charles Chan0f43e472017-02-14 14:00:16 -0800274
275 return DefaultFlowRule.builder()
276 .forDevice(deviceId)
277 .withSelector(sbuilder.build())
278 .withTreatment(tbuilder.build())
279 .withPriority(PacketPriority.CONTROL.priorityValue())
280 .fromApp(driverId)
281 .makePermanent()
282 .forTable(PUNT_TABLE).build();
283 }
284
285 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800286 * Builds a punt to the controller rule for the arp protocol.
Charles Chan0f43e472017-02-14 14:00:16 -0800287 * <p>
288 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
289 * pop VLAN before sending to controller disregarding whether
290 * it's an internally assigned VLAN or a natural VLAN.
291 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800292 *
293 * @param assignedVlan the internal assigned vlan id
294 * @param applicationId the application id
295 * @return the punt flow rule for the arp
296 */
297 private FlowRule buildArpPunt(VlanId assignedVlan, ApplicationId applicationId) {
298 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
299 .matchEthType(Ethernet.TYPE_ARP)
300 .matchVlanId(assignedVlan);
301 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
302 .popVlan()
303 .punt();
304
305 return DefaultFlowRule.builder()
306 .forDevice(deviceId)
307 .withSelector(sbuilder.build())
308 .withTreatment(tbuilder.build())
309 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
310 .fromApp(applicationId)
311 .makePermanent()
312 .forTable(ACL_TABLE).build();
313 }
314
315 /**
316 * Builds a punt to the controller rule for the icmp v6 messages.
Charles Chan0f43e472017-02-14 14:00:16 -0800317 * <p>
318 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
319 * pop VLAN before sending to controller disregarding whether
320 * it's an internally assigned VLAN or a natural VLAN.
321 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800322 *
323 * @param assignedVlan the internal assigned vlan id
324 * @param applicationId the application id
325 * @return the punt flow rule for the icmp v6 messages
326 */
327 private FlowRule buildIcmpV6Punt(VlanId assignedVlan, ApplicationId applicationId) {
328 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
329 .matchVlanId(assignedVlan)
330 .matchEthType(Ethernet.TYPE_IPV6)
331 .matchIPProtocol(PROTOCOL_ICMP6);
332 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
333 .popVlan()
334 .punt();
335
336 return DefaultFlowRule.builder()
337 .forDevice(deviceId)
338 .withSelector(sbuilder.build())
339 .withTreatment(tbuilder.build())
340 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
341 .fromApp(applicationId)
342 .makePermanent()
343 .forTable(ACL_TABLE).build();
344 }
345
Saurav Das4ce45962015-11-24 23:21:05 -0800346 /*
347 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
348 * Workaround requires popping off the VLAN tags in the TMAC table.
349 *
350 * (non-Javadoc)
351 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
352 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800353 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800354 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das4ce45962015-11-24 23:21:05 -0800355 EthCriterion ethCriterion,
356 VlanIdCriterion vidCriterion,
357 VlanId assignedVlan,
Charles Chand57552d2018-03-02 15:41:41 -0800358 MacAddress unicastMac,
Saurav Das4ce45962015-11-24 23:21:05 -0800359 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800360 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
361 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
362 return processEthDstOnlyFilter(ethCriterion, applicationId);
363 }
364
Charles Chan5b9df8d2016-03-28 22:21:40 -0700365 // Multicast MAC
366 if (ethCriterion.mask() != null) {
Charles Chand57552d2018-03-02 15:41:41 -0800367 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700368 }
369
Saurav Das4ce45962015-11-24 23:21:05 -0800370 //handling untagged packets via assigned VLAN
371 if (vidCriterion.vlanId() == VlanId.NONE) {
372 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
373 }
374 // ofdpa cannot match on ALL portnumber, so we need to use separate
375 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800376 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800377 if (portCriterion != null) {
378 if (portCriterion.port() == PortNumber.ALL) {
379 for (Port port : deviceService.getPorts(deviceId)) {
380 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
381 portnums.add(port.number());
382 }
Saurav Das4ce45962015-11-24 23:21:05 -0800383 }
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800384 } else {
385 portnums.add(portCriterion.port());
Saurav Das4ce45962015-11-24 23:21:05 -0800386 }
Saurav Das4ce45962015-11-24 23:21:05 -0800387 }
388
Charles Chan93090352018-03-02 13:26:22 -0800389 List<FlowRule> rules = new ArrayList<>();
Saurav Das4ce45962015-11-24 23:21:05 -0800390 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800391 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800392 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
393 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
394 selector.matchInPort(pnum);
395 selector.matchVlanId(vidCriterion.vlanId());
396 selector.matchEthType(Ethernet.TYPE_IPV4);
397 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800398 if (!supportTaggedMpls()) {
399 treatment.popVlan();
400 }
Saurav Das4ce45962015-11-24 23:21:05 -0800401 treatment.transition(UNICAST_ROUTING_TABLE);
402 FlowRule rule = DefaultFlowRule.builder()
403 .forDevice(deviceId)
404 .withSelector(selector.build())
405 .withTreatment(treatment.build())
406 .withPriority(DEFAULT_PRIORITY)
407 .fromApp(applicationId)
408 .makePermanent()
409 .forTable(TMAC_TABLE).build();
410 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800411
412 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800413 selector = DefaultTrafficSelector.builder();
414 treatment = DefaultTrafficTreatment.builder();
415 selector.matchInPort(pnum);
416 selector.matchVlanId(vidCriterion.vlanId());
417 selector.matchEthType(Ethernet.MPLS_UNICAST);
418 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800419 if (!supportTaggedMpls()) {
420 treatment.popVlan();
421 }
Saurav Das4ce45962015-11-24 23:21:05 -0800422 treatment.transition(MPLS_TABLE_0);
423 rule = DefaultFlowRule.builder()
424 .forDevice(deviceId)
425 .withSelector(selector.build())
426 .withTreatment(treatment.build())
427 .withPriority(DEFAULT_PRIORITY)
428 .fromApp(applicationId)
429 .makePermanent()
430 .forTable(TMAC_TABLE).build();
431 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800432
433 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800434 selector = DefaultTrafficSelector.builder();
435 treatment = DefaultTrafficTreatment.builder();
436 selector.matchInPort(pnum);
437 selector.matchVlanId(vidCriterion.vlanId());
438 selector.matchEthType(Ethernet.TYPE_IPV6);
439 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800440 if (!supportTaggedMpls()) {
441 treatment.popVlan();
442 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800443 treatment.transition(UNICAST_ROUTING_TABLE);
444 rule = DefaultFlowRule.builder()
445 .forDevice(deviceId)
446 .withSelector(selector.build())
447 .withTreatment(treatment.build())
448 .withPriority(DEFAULT_PRIORITY)
449 .fromApp(applicationId)
450 .makePermanent()
451 .forTable(TMAC_TABLE).build();
452 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800453 }
Charles Chan206506b2018-03-02 16:43:28 -0800454 return ImmutableList.of(rules);
Saurav Das4ce45962015-11-24 23:21:05 -0800455 }
456
Charles Chan5270ed02016-01-30 23:22:37 -0800457 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800458 protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700459 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800460 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
461 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
462 selector.matchEthType(Ethernet.TYPE_IPV4);
463 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800464 if (!supportTaggedMpls()) {
465 treatment.popVlan();
466 }
Charles Chan5270ed02016-01-30 23:22:37 -0800467 treatment.transition(UNICAST_ROUTING_TABLE);
468 FlowRule rule = DefaultFlowRule.builder()
469 .forDevice(deviceId)
470 .withSelector(selector.build())
471 .withTreatment(treatment.build())
472 .withPriority(DEFAULT_PRIORITY)
473 .fromApp(applicationId)
474 .makePermanent()
475 .forTable(TMAC_TABLE).build();
Charles Chan206506b2018-03-02 16:43:28 -0800476 return ImmutableList.of(ImmutableList.of(rule));
Charles Chan5270ed02016-01-30 23:22:37 -0800477 }
478
Saurav Das4ce45962015-11-24 23:21:05 -0800479 /*
480 * Cpqd emulation allows MPLS ecmp.
481 *
482 * (non-Javadoc)
483 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
484 */
485 @Override
486 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800487 TrafficSelector selector = fwd.selector();
488 EthTypeCriterion ethType =
489 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
490 if ((ethType == null) ||
491 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800492 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
493 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800494 log.warn("processSpecific: Unsupported forwarding objective criteria"
495 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800496 fail(fwd, ObjectiveError.UNSUPPORTED);
497 return Collections.emptySet();
498 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800499 boolean defaultRule = false;
Charles Chan93090352018-03-02 13:26:22 -0800500 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800501 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800502 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
503
Saurav Das8a0732e2015-11-20 15:27:53 -0800504 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800505 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700506 if (ipv4Dst.isMulticast()) {
507 if (ipv4Dst.prefixLength() != 32) {
508 log.warn("Multicast specific forwarding objective can only be /32");
509 fail(fwd, ObjectiveError.BADPARAMS);
510 return ImmutableSet.of();
511 }
512 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
513 if (assignedVlan == null) {
514 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
515 fail(fwd, ObjectiveError.BADPARAMS);
516 return ImmutableSet.of();
517 }
518 filteredSelector.matchVlanId(assignedVlan);
519 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
520 forTableId = MULTICAST_ROUTING_TABLE;
521 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
522 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800523 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700524 if (ipv4Dst.prefixLength() == 0) {
525 // The entire IPV4_DST field is wildcarded intentionally
526 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700527 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700528 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700529 }
530 forTableId = UNICAST_ROUTING_TABLE;
531 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
532 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800533 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800534 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
Julia Ferguson65428c32017-08-10 18:15:24 +0000535 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
536 if (ipv6Dst.isMulticast()) {
537 if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
538 log.debug("Multicast specific IPv6 forwarding objective can only be /128");
539 fail(fwd, ObjectiveError.BADPARAMS);
540 return ImmutableSet.of();
541 }
542 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
543 if (assignedVlan == null) {
544 log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
545 fail(fwd, ObjectiveError.BADPARAMS);
546 return ImmutableSet.of();
547 }
548 filteredSelector.matchVlanId(assignedVlan);
549 filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
550 forTableId = MULTICAST_ROUTING_TABLE;
551 log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
552 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
553 } else {
554 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
555 return Collections.emptyList();
556 }
557 forTableId = UNICAST_ROUTING_TABLE;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800558 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800559 } else {
560 filteredSelector
561 .matchEthType(Ethernet.MPLS_UNICAST)
562 .matchMplsLabel(((MplsCriterion)
563 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
564 MplsBosCriterion bos = (MplsBosCriterion) selector
565 .getCriterion(Criterion.Type.MPLS_BOS);
566 if (bos != null) {
567 filteredSelector.matchMplsBos(bos.mplsBos());
568 }
569 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800570 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
571 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800572 }
573
574 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
575 if (fwd.treatment() != null) {
576 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan40132b32017-01-22 00:19:37 -0800577 if (!supportCopyTtl() && i instanceof L3ModificationInstruction) {
578 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
579 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
580 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
581 continue;
582 }
583 }
Charles Chan7d10b162015-12-07 18:54:45 -0800584 /*
585 * NOTE: OF-DPA does not support immediate instruction in
586 * L3 unicast and MPLS table.
587 */
588 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800589 }
590 }
591
592 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800593 NextGroup next = getGroupForNextObjective(fwd.nextId());
594 if (next != null) {
595 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
596 // we only need the top level group's key to point the flow to it
597 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
598 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700599 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
600 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800601 fail(fwd, ObjectiveError.GROUPMISSING);
602 return Collections.emptySet();
603 }
604 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800605 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800606 }
607 tb.transition(ACL_TABLE);
608 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
609 .fromApp(fwd.appId())
610 .withPriority(fwd.priority())
611 .forDevice(deviceId)
612 .withSelector(filteredSelector.build())
613 .withTreatment(tb.build())
614 .forTable(forTableId);
615
616 if (fwd.permanent()) {
617 ruleBuilder.makePermanent();
618 } else {
619 ruleBuilder.makeTemporary(fwd.timeout());
620 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800621 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
622 flowRuleCollection.add(ruleBuilder.build());
623 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800624 flowRuleCollection.add(
625 defaultRoute(fwd, complementarySelector, forTableId, tb)
626 );
Flavio Castroe10fa242016-01-15 12:43:51 -0800627 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
628 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800629 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800630 }
631
Charles Chan1e492d32016-01-30 23:22:37 -0800632 @Override
633 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
634 List<FlowRule> rules = new ArrayList<>();
635
636 // Build filtered selector
637 TrafficSelector selector = fwd.selector();
638 EthCriterion ethCriterion = (EthCriterion) selector
639 .getCriterion(Criterion.Type.ETH_DST);
640 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
641 .getCriterion(Criterion.Type.VLAN_VID);
642
643 if (vlanIdCriterion == null) {
644 log.warn("Forwarding objective for bridging requires vlan. Not "
645 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
646 fail(fwd, ObjectiveError.BADPARAMS);
647 return Collections.emptySet();
648 }
649
650 TrafficSelector.Builder filteredSelectorBuilder =
651 DefaultTrafficSelector.builder();
652 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -0800653 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -0800654 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
655 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
656 fwd.id(), fwd.nextId(), deviceId);
657 } else {
658 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
659 + "in dev:{} for vlan:{}",
660 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
661 }
662 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
663 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
664
665 if (fwd.treatment() != null) {
666 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
667 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
668 }
669
670 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
671 if (fwd.nextId() != null) {
672 NextGroup next = getGroupForNextObjective(fwd.nextId());
673 if (next != null) {
674 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
675 // we only need the top level group's key to point the flow to it
676 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
677 if (group != null) {
678 treatmentBuilder.deferred().group(group.id());
679 } else {
680 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
681 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
682 fail(fwd, ObjectiveError.GROUPMISSING);
683 return Collections.emptySet();
684 }
685 }
686 }
687 treatmentBuilder.immediate().transition(ACL_TABLE);
688 TrafficTreatment filteredTreatment = treatmentBuilder.build();
689
690 // Build bridging table entries
691 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
692 flowRuleBuilder.fromApp(fwd.appId())
693 .withPriority(fwd.priority())
694 .forDevice(deviceId)
695 .withSelector(filteredSelector)
696 .withTreatment(filteredTreatment)
697 .forTable(BRIDGING_TABLE);
698 if (fwd.permanent()) {
699 flowRuleBuilder.makePermanent();
700 } else {
701 flowRuleBuilder.makeTemporary(fwd.timeout());
702 }
703 rules.add(flowRuleBuilder.build());
704 return rules;
705 }
706
Saurav Das52025962016-01-28 22:30:01 -0800707 /*
708 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
709 * ACL table. Because we pop off vlan tags in TMAC table,
710 * we need to avoid matching on vlans in the ACL table.
711 */
712 @Override
713 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
714 log.info("Processing versatile forwarding objective");
715
716 EthTypeCriterion ethType =
717 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
718 if (ethType == null) {
719 log.error("Versatile forwarding objective must include ethType");
720 fail(fwd, ObjectiveError.BADPARAMS);
721 return Collections.emptySet();
722 }
723 if (fwd.nextId() == null && fwd.treatment() == null) {
724 log.error("Forwarding objective {} from {} must contain "
725 + "nextId or Treatment", fwd.selector(), fwd.appId());
726 return Collections.emptySet();
727 }
728
729 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
730 fwd.selector().criteria().forEach(criterion -> {
731 if (criterion instanceof VlanIdCriterion) {
732 // avoid matching on vlans
733 return;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800734 } else if (criterion instanceof Icmpv6TypeCriterion ||
735 criterion instanceof Icmpv6CodeCriterion) {
736 /*
737 * We silenty discard these criterions, our current
738 * OFDPA platform does not support these matches on
739 * the ACL table.
740 */
741 log.warn("ICMPv6 Type and ICMPv6 Code are not supported");
Saurav Das52025962016-01-28 22:30:01 -0800742 } else {
743 sbuilder.add(criterion);
744 }
745 });
746
747 // XXX driver does not currently do type checking as per Tables 65-67 in
748 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
749 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
750 if (fwd.treatment() != null) {
751 for (Instruction ins : fwd.treatment().allInstructions()) {
752 if (ins instanceof OutputInstruction) {
753 OutputInstruction o = (OutputInstruction) ins;
754 if (o.port() == PortNumber.CONTROLLER) {
Charles Chan0f43e472017-02-14 14:00:16 -0800755 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -0800756 } else {
757 log.warn("Only allowed treatments in versatile forwarding "
758 + "objectives are punts to the controller");
759 }
760 } else {
761 log.warn("Cannot process instruction in versatile fwd {}", ins);
762 }
763 }
Charles Chan2df0e8a2017-01-09 11:45:08 -0800764 if (fwd.treatment().clearedDeferred()) {
765 ttBuilder.wipeDeferred();
766 }
Saurav Das52025962016-01-28 22:30:01 -0800767 }
768 if (fwd.nextId() != null) {
769 // overide case
770 NextGroup next = getGroupForNextObjective(fwd.nextId());
771 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
772 // we only need the top level group's key to point the flow to it
773 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
774 if (group == null) {
775 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
776 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
777 fail(fwd, ObjectiveError.GROUPMISSING);
778 return Collections.emptySet();
779 }
780 ttBuilder.deferred().group(group.id());
781 }
782
783 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
784 .fromApp(fwd.appId())
785 .withPriority(fwd.priority())
786 .forDevice(deviceId)
787 .withSelector(sbuilder.build())
788 .withTreatment(ttBuilder.build())
789 .makePermanent()
790 .forTable(ACL_TABLE);
791 return Collections.singletonList(ruleBuilder.build());
792 }
793
794 /*
795 * Cpqd emulation requires table-miss-entries in forwarding tables.
796 * Real OFDPA does not require these rules as they are put in by default.
797 *
798 * (non-Javadoc)
799 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
800 */
Saurav Das2857f382015-11-03 14:39:27 -0800801 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700802 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -0800803 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
804 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
805 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
806 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
807 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
808 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
809 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
810 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
811 initTableMiss(ACL_TABLE, -1, null);
Charles Chan0f43e472017-02-14 14:00:16 -0800812
813 if (supportPuntGroup()) {
814 initTableMiss(PUNT_TABLE, -1,
815 DefaultTrafficTreatment.builder().punt().build());
816 initPopVlanPuntGroup();
817 } else {
818 initTableMiss(PUNT_TABLE, -1,
819 DefaultTrafficTreatment.builder().popVlan().punt().build());
820 }
Saurav Das558afec2015-05-31 17:12:48 -0700821 }
822
Charles Chanf6ec1532017-02-08 16:10:40 -0800823 /**
824 * Install table-miss flow entry.
825 *
826 * If treatment exists, use it directly.
827 * Else if treatment does not exist but nextTable > 0, transit to next table.
828 * Else apply empty treatment.
829 *
830 * @param thisTable this table ID
831 * @param nextTable next table ID
832 * @param treatment traffic treatment to apply.
833 */
834 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -0700835 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -0800836 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -0700837
Charles Chanf6ec1532017-02-08 16:10:40 -0800838 if (treatment == null) {
839 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
840 if (nextTable > 0) {
841 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -0700842 }
Charles Chanf6ec1532017-02-08 16:10:40 -0800843 treatment = tBuilder.build();
844 }
Saurav Das558afec2015-05-31 17:12:48 -0700845
Charles Chanb7504392017-02-10 12:51:04 -0800846 FlowRule rule = DefaultFlowRule.builder()
847 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -0800848 .withSelector(selector)
849 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -0800850 .withPriority(LOWEST_PRIORITY)
851 .fromApp(driverId)
852 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -0800853 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -0800854 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -0800855
856 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
857 @Override
858 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800859 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800860 }
Saurav Das2857f382015-11-03 14:39:27 -0800861 @Override
862 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800863 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800864 }
865 }));
866 }
Charles Chan0f43e472017-02-14 14:00:16 -0800867
868 /**
869 * Builds a indirect group contains pop_vlan and punt actions.
870 * <p>
871 * Using group instead of immediate action to ensure that
872 * the copy of packet on the data plane is not affected by the pop vlan action.
873 */
874 private void initPopVlanPuntGroup() {
Yi Tsengef19de12017-04-24 11:33:05 -0700875 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -0800876 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
877 .popVlan().punt().build();
878 GroupBucket bucket =
879 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
880 GroupDescription groupDesc =
881 new DefaultGroupDescription(
882 deviceId,
883 GroupDescription.Type.INDIRECT,
884 new GroupBuckets(Collections.singletonList(bucket)),
885 groupKey,
886 POP_VLAN_PUNT_GROUP_ID,
887 driverId);
888 groupService.addGroup(groupDesc);
889
890 log.info("Initialized pop vlan punt group on {}", deviceId);
891 }
Yi Tsengef19de12017-04-24 11:33:05 -0700892
893 /**
894 * Generates group key for a static indirect group that pop vlan and punt to
895 * controller.
896 *
897 * @return the group key of the indirect table
898 */
899 private GroupKey popVlanPuntGroupKey() {
900 int hash = POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_BIT_MASK);
901 return new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(hash));
902 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700903
904 private class PopVlanPuntGroupChecker implements Runnable {
905 @Override
906 public void run() {
907
908 Group group = groupService.getGroup(deviceId, popVlanPuntGroupKey());
909 if (group != null) {
910 // shutdown the executor
911 if (!groupChecker.isShutdown()) {
912 groupChecker.shutdown();
913 }
914 // if we have pending flow rules install them
915 if (flowRuleQueue.size() > 0) {
916 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
917 // we should not care about the context here, it can only be add
918 // since when removing the rules the group should be there already.
919 flowRuleQueue.forEach(ops::add);
920 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
921 @Override
922 public void onSuccess(FlowRuleOperations ops) {
923 log.debug("Applied {} pop vlan punt rules in device {}",
924 ops.stages().get(0).size(), deviceId);
925 }
926 @Override
927 public void onError(FlowRuleOperations ops) {
928 log.error("Failed to apply all pop vlan punt rules in dev {}", deviceId);
929 }
930 }));
931 }
932 }
933 }
934 }
Saurav Das558afec2015-05-31 17:12:48 -0700935}