blob: 140513cd17cb6740e5b7dc819751013aa259f743 [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 Chan3fe71712018-06-15 18:54:18 -070053import org.onosproject.net.flow.instructions.Instructions.NoActionInstruction;
Charles Chan40132b32017-01-22 00:19:37 -080054import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Saurav Das8a0732e2015-11-20 15:27:53 -080055import org.onosproject.net.flowobjective.ForwardingObjective;
56import org.onosproject.net.flowobjective.ObjectiveError;
Charles Chan0f43e472017-02-14 14:00:16 -080057import org.onosproject.net.group.DefaultGroupBucket;
58import org.onosproject.net.group.DefaultGroupDescription;
59import org.onosproject.net.group.DefaultGroupKey;
Saurav Das8a0732e2015-11-20 15:27:53 -080060import org.onosproject.net.group.Group;
Charles Chan0f43e472017-02-14 14:00:16 -080061import org.onosproject.net.group.GroupBucket;
62import org.onosproject.net.group.GroupBuckets;
63import org.onosproject.net.group.GroupDescription;
Saurav Das8a0732e2015-11-20 15:27:53 -080064import org.onosproject.net.group.GroupKey;
Charles Chanf57a8252016-06-29 19:12:37 -070065import org.onosproject.net.packet.PacketPriority;
Saurav Das558afec2015-05-31 17:12:48 -070066import org.slf4j.Logger;
67
Jonathan Hart855179c2016-04-26 07:40:04 -070068import java.util.ArrayList;
69import java.util.Collection;
70import java.util.Collections;
71import java.util.Deque;
72import java.util.List;
Charles Chan0f43e472017-02-14 14:00:16 -080073import java.util.Objects;
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -070074import java.util.Queue;
75import java.util.concurrent.ConcurrentLinkedQueue;
76import java.util.concurrent.Executors;
77import java.util.concurrent.ScheduledExecutorService;
78import java.util.concurrent.TimeUnit;
Jonathan Hart855179c2016-04-26 07:40:04 -070079
Pier Ventree0ae7a32016-11-23 09:57:42 -080080import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Charles Chand05f54b2017-02-13 11:56:54 -080081import static org.onlab.packet.MacAddress.BROADCAST;
82import static org.onlab.packet.MacAddress.NONE;
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -070083import static org.onlab.util.Tools.groupedThreads;
Yi Tsengef19de12017-04-24 11:33:05 -070084import static org.onosproject.driver.pipeline.ofdpa.OfdpaGroupHandlerUtility.*;
Jonathan Hart855179c2016-04-26 07:40:04 -070085import static org.slf4j.LoggerFactory.getLogger;
86
Saurav Das558afec2015-05-31 17:12:48 -070087
88/**
Charles Chan40132b32017-01-22 00:19:37 -080089 * Driver for software switch emulation of the OFDPA pipeline.
Saurav Das52025962016-01-28 22:30:01 -080090 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
91 * does not handle vlan tags and mpls labels simultaneously, which requires us
92 * to do some workarounds in the driver. This driver is meant for the use of
93 * the cpqd switch when MPLS is required. As a result this driver works only
94 * on incoming untagged packets.
Saurav Das558afec2015-05-31 17:12:48 -070095 */
Charles Chan361154b2016-03-24 10:23:39 -070096public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -070097
98 private final Logger log = getLogger(getClass());
99
Charles Chan40132b32017-01-22 00:19:37 -0800100 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800101 * Table that determines whether VLAN is popped before punting to controller.
102 * <p>
103 * This is a non-OFDPA table to emulate OFDPA packet in behavior.
104 * VLAN will be popped before punting if the VLAN is internally assigned.
105 * <p>
106 * Also note that 63 is the max table number in CpqD.
107 */
108 private static final int PUNT_TABLE = 63;
109
110 /**
111 * A static indirect group that pop vlan and punt to controller.
112 * <p>
113 * The purpose of using a group instead of immediate action is that this
114 * won't affect another copy on the data plane when write action exists.
115 */
116 private static final int POP_VLAN_PUNT_GROUP_ID = 0xc0000000;
117
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700118 /**
119 * Executor for group checker thread that checks pop vlan punt group.
120 */
121 private ScheduledExecutorService groupChecker;
122
123 /**
124 * Queue for passing pop vlan punt group flow rules to the GroupChecker thread.
125 */
126 private Queue<FlowRule> flowRuleQueue = new ConcurrentLinkedQueue<>();
127
Charles Chan053b1cb2017-03-22 16:56:35 -0700128 @Override
129 protected boolean requireVlanExtensions() {
130 return false;
131 }
132
Charles Chan0f43e472017-02-14 14:00:16 -0800133 /**
Charles Chan40132b32017-01-22 00:19:37 -0800134 * Determines whether this pipeline support copy ttl instructions or not.
135 *
136 * @return true if copy ttl instructions are supported
137 */
138 protected boolean supportCopyTtl() {
139 return true;
140 }
141
Charles Chan0f43e472017-02-14 14:00:16 -0800142 /**
143 * Determines whether this pipeline support push mpls to vlan-tagged packets or not.
144 * <p>
145 * If not support, pop vlan before push entering unicast and mpls table.
146 * Side effect: HostService learns redundant hosts with same MAC but
147 * different VLAN. No known side effect on the network reachability.
148 *
149 * @return true if push mpls to vlan-tagged packets is supported
150 */
151 protected boolean supportTaggedMpls() {
152 return false;
153 }
154
155 /**
156 * Determines whether this pipeline support punt action in group bucket.
157 *
158 * @return true if punt action in group bucket is supported
159 */
160 protected boolean supportPuntGroup() {
161 return false;
162 }
163
Charles Chan425854b2016-04-11 15:32:12 -0700164 @Override
Charles Chan40132b32017-01-22 00:19:37 -0800165 protected void initDriverId() {
Charles Chan425854b2016-04-11 15:32:12 -0700166 driverId = coreService.registerApplication(
167 "org.onosproject.driver.CpqdOfdpa2Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -0800168 }
Charles Chan425854b2016-04-11 15:32:12 -0700169
Charles Chan40132b32017-01-22 00:19:37 -0800170 @Override
171 protected void initGroupHander(PipelinerContext context) {
172 groupHandler = new CpqdOfdpa2GroupHandler();
173 groupHandler.init(deviceId, context);
Charles Chan425854b2016-04-11 15:32:12 -0700174 }
175
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700176 @Override
177 public void init(DeviceId deviceId, PipelinerContext context) {
178
179 // create a new executor at each init
180 groupChecker = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/driver",
181 "cpqd-ofdpa-%d", log));
182 groupChecker.scheduleAtFixedRate(new PopVlanPuntGroupChecker(), 100, 300, TimeUnit.MILLISECONDS);
183 super.init(deviceId, context);
184 }
Saurav Das4ce45962015-11-24 23:21:05 -0800185 /*
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700186 * Cpqd emulation does not require the non OF-standard rules for
187 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800188 *
189 * (non-Javadoc)
190 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
191 */
Saurav Das558afec2015-05-31 17:12:48 -0700192 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800193 protected List<List<FlowRule>> processVlanIdFilter(PortCriterion portCriterion,
Saurav Das2857f382015-11-03 14:39:27 -0800194 VlanIdCriterion vidCriterion,
195 VlanId assignedVlan,
196 ApplicationId applicationId) {
Charles Chan79769232016-07-05 16:34:39 -0700197 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800198 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
199 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
200 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800201 treatment.transition(TMAC_TABLE);
202
Saurav Das2857f382015-11-03 14:39:27 -0800203 if (vidCriterion.vlanId() == VlanId.NONE) {
204 // untagged packets are assigned vlans
205 treatment.pushVlan().setVlanId(assignedVlan);
Pier3cc7e662018-03-07 11:42:50 +0100206 } else if (!vidCriterion.vlanId().equals(assignedVlan)) {
207 // Rewrite with assigned vlans
208 treatment.setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800209 }
Saurav Das2857f382015-11-03 14:39:27 -0800210
211 // ofdpa cannot match on ALL portnumber, so we need to use separate
212 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800213 List<PortNumber> portnums = new ArrayList<>();
Ray Milkey94542b02018-05-10 12:42:51 -0700214 if (portCriterion != null) {
215 if (portCriterion.port() == PortNumber.ALL) {
216 for (Port port : deviceService.getPorts(deviceId)) {
217 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
218 portnums.add(port.number());
219 }
Saurav Das2857f382015-11-03 14:39:27 -0800220 }
Ray Milkey94542b02018-05-10 12:42:51 -0700221 } else {
222 portnums.add(portCriterion.port());
Saurav Das2857f382015-11-03 14:39:27 -0800223 }
Saurav Das2857f382015-11-03 14:39:27 -0800224 }
Saurav Das4f980082015-11-05 13:39:15 -0800225
Saurav Das2857f382015-11-03 14:39:27 -0800226 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800227 // NOTE: Emulating OFDPA behavior by popping off internal assigned
228 // VLAN before sending to controller
229 if (supportPuntGroup() && vidCriterion.vlanId() == VlanId.NONE) {
Yi Tsengef19de12017-04-24 11:33:05 -0700230 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -0800231 Group group = groupService.getGroup(deviceId, groupKey);
232 if (group != null) {
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700233 if (!groupChecker.isShutdown()) {
234 groupChecker.shutdown();
235 }
Charles Chan0f43e472017-02-14 14:00:16 -0800236 rules.add(buildPuntTableRule(pnum, assignedVlan));
237 } else {
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700238 // The VLAN punt group may be held back due to device initial audit.
239 // In that case, we queue all punt table flow until the group has been created.
240 log.info("popVlanPuntGroup not found in dev:{}, queueing this flow rule.", deviceId);
241 flowRuleQueue.add(buildPuntTableRule(pnum, assignedVlan));
Charles Chan0f43e472017-02-14 14:00:16 -0800242 }
243 }
244
Saurav Das4f980082015-11-05 13:39:15 -0800245 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800246 selector.matchInPort(pnum);
247 FlowRule rule = DefaultFlowRule.builder()
248 .forDevice(deviceId)
249 .withSelector(selector.build())
250 .withTreatment(treatment.build())
251 .withPriority(DEFAULT_PRIORITY)
252 .fromApp(applicationId)
253 .makePermanent()
254 .forTable(VLAN_TABLE).build();
255 rules.add(rule);
256 }
Charles Chanf57a8252016-06-29 19:12:37 -0700257
Charles Chan206506b2018-03-02 16:43:28 -0800258 return ImmutableList.of(rules);
Saurav Das2857f382015-11-03 14:39:27 -0800259 }
260
Pier Ventree0ae7a32016-11-23 09:57:42 -0800261 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800262 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
263 * a group that pop vlan and punt.
264 *
265 * @param portNumber port number
266 * @param assignedVlan internally assigned vlan id
267 * @return punt table flow rule
268 */
269 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
270 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
271 .matchInPort(portNumber)
272 .matchVlanId(assignedVlan);
273 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
Yi Tsengfa394de2017-02-01 11:26:40 -0800274 .group(new GroupId(POP_VLAN_PUNT_GROUP_ID));
Charles Chan0f43e472017-02-14 14:00:16 -0800275
276 return DefaultFlowRule.builder()
277 .forDevice(deviceId)
278 .withSelector(sbuilder.build())
279 .withTreatment(tbuilder.build())
280 .withPriority(PacketPriority.CONTROL.priorityValue())
281 .fromApp(driverId)
282 .makePermanent()
283 .forTable(PUNT_TABLE).build();
284 }
285
286 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800287 * Builds a punt to the controller rule for the arp protocol.
Charles Chan0f43e472017-02-14 14:00:16 -0800288 * <p>
289 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
290 * pop VLAN before sending to controller disregarding whether
291 * it's an internally assigned VLAN or a natural VLAN.
292 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800293 *
294 * @param assignedVlan the internal assigned vlan id
295 * @param applicationId the application id
296 * @return the punt flow rule for the arp
297 */
298 private FlowRule buildArpPunt(VlanId assignedVlan, ApplicationId applicationId) {
299 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
300 .matchEthType(Ethernet.TYPE_ARP)
301 .matchVlanId(assignedVlan);
302 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
303 .popVlan()
304 .punt();
305
306 return DefaultFlowRule.builder()
307 .forDevice(deviceId)
308 .withSelector(sbuilder.build())
309 .withTreatment(tbuilder.build())
310 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
311 .fromApp(applicationId)
312 .makePermanent()
313 .forTable(ACL_TABLE).build();
314 }
315
316 /**
317 * Builds a punt to the controller rule for the icmp v6 messages.
Charles Chan0f43e472017-02-14 14:00:16 -0800318 * <p>
319 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
320 * pop VLAN before sending to controller disregarding whether
321 * it's an internally assigned VLAN or a natural VLAN.
322 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800323 *
324 * @param assignedVlan the internal assigned vlan id
325 * @param applicationId the application id
326 * @return the punt flow rule for the icmp v6 messages
327 */
328 private FlowRule buildIcmpV6Punt(VlanId assignedVlan, ApplicationId applicationId) {
329 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
330 .matchVlanId(assignedVlan)
331 .matchEthType(Ethernet.TYPE_IPV6)
332 .matchIPProtocol(PROTOCOL_ICMP6);
333 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
334 .popVlan()
335 .punt();
336
337 return DefaultFlowRule.builder()
338 .forDevice(deviceId)
339 .withSelector(sbuilder.build())
340 .withTreatment(tbuilder.build())
341 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
342 .fromApp(applicationId)
343 .makePermanent()
344 .forTable(ACL_TABLE).build();
345 }
346
Saurav Das4ce45962015-11-24 23:21:05 -0800347 /*
348 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
349 * Workaround requires popping off the VLAN tags in the TMAC table.
350 *
351 * (non-Javadoc)
352 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
353 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800354 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800355 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das4ce45962015-11-24 23:21:05 -0800356 EthCriterion ethCriterion,
357 VlanIdCriterion vidCriterion,
358 VlanId assignedVlan,
Charles Chand57552d2018-03-02 15:41:41 -0800359 MacAddress unicastMac,
Saurav Das4ce45962015-11-24 23:21:05 -0800360 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800361 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
362 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
363 return processEthDstOnlyFilter(ethCriterion, applicationId);
364 }
365
Charles Chan5b9df8d2016-03-28 22:21:40 -0700366 // Multicast MAC
367 if (ethCriterion.mask() != null) {
Charles Chand57552d2018-03-02 15:41:41 -0800368 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700369 }
370
Saurav Das4ce45962015-11-24 23:21:05 -0800371 //handling untagged packets via assigned VLAN
372 if (vidCriterion.vlanId() == VlanId.NONE) {
373 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
374 }
375 // ofdpa cannot match on ALL portnumber, so we need to use separate
376 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800377 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800378 if (portCriterion != null) {
379 if (portCriterion.port() == PortNumber.ALL) {
380 for (Port port : deviceService.getPorts(deviceId)) {
381 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
382 portnums.add(port.number());
383 }
Saurav Das4ce45962015-11-24 23:21:05 -0800384 }
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800385 } else {
386 portnums.add(portCriterion.port());
Saurav Das4ce45962015-11-24 23:21:05 -0800387 }
Saurav Das4ce45962015-11-24 23:21:05 -0800388 }
389
Charles Chan93090352018-03-02 13:26:22 -0800390 List<FlowRule> rules = new ArrayList<>();
Saurav Das4ce45962015-11-24 23:21:05 -0800391 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800392 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800393 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
394 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
395 selector.matchInPort(pnum);
396 selector.matchVlanId(vidCriterion.vlanId());
397 selector.matchEthType(Ethernet.TYPE_IPV4);
398 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800399 if (!supportTaggedMpls()) {
400 treatment.popVlan();
401 }
Saurav Das4ce45962015-11-24 23:21:05 -0800402 treatment.transition(UNICAST_ROUTING_TABLE);
403 FlowRule rule = DefaultFlowRule.builder()
404 .forDevice(deviceId)
405 .withSelector(selector.build())
406 .withTreatment(treatment.build())
407 .withPriority(DEFAULT_PRIORITY)
408 .fromApp(applicationId)
409 .makePermanent()
410 .forTable(TMAC_TABLE).build();
411 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800412
413 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800414 selector = DefaultTrafficSelector.builder();
415 treatment = DefaultTrafficTreatment.builder();
416 selector.matchInPort(pnum);
417 selector.matchVlanId(vidCriterion.vlanId());
418 selector.matchEthType(Ethernet.MPLS_UNICAST);
419 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800420 if (!supportTaggedMpls()) {
421 treatment.popVlan();
422 }
Saurav Das4ce45962015-11-24 23:21:05 -0800423 treatment.transition(MPLS_TABLE_0);
424 rule = DefaultFlowRule.builder()
425 .forDevice(deviceId)
426 .withSelector(selector.build())
427 .withTreatment(treatment.build())
428 .withPriority(DEFAULT_PRIORITY)
429 .fromApp(applicationId)
430 .makePermanent()
431 .forTable(TMAC_TABLE).build();
432 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800433
434 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800435 selector = DefaultTrafficSelector.builder();
436 treatment = DefaultTrafficTreatment.builder();
437 selector.matchInPort(pnum);
438 selector.matchVlanId(vidCriterion.vlanId());
439 selector.matchEthType(Ethernet.TYPE_IPV6);
440 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800441 if (!supportTaggedMpls()) {
442 treatment.popVlan();
443 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800444 treatment.transition(UNICAST_ROUTING_TABLE);
445 rule = DefaultFlowRule.builder()
446 .forDevice(deviceId)
447 .withSelector(selector.build())
448 .withTreatment(treatment.build())
449 .withPriority(DEFAULT_PRIORITY)
450 .fromApp(applicationId)
451 .makePermanent()
452 .forTable(TMAC_TABLE).build();
453 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800454 }
Charles Chan206506b2018-03-02 16:43:28 -0800455 return ImmutableList.of(rules);
Saurav Das4ce45962015-11-24 23:21:05 -0800456 }
457
Charles Chan5270ed02016-01-30 23:22:37 -0800458 @Override
Charles Chan206506b2018-03-02 16:43:28 -0800459 protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700460 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800461 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
462 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
463 selector.matchEthType(Ethernet.TYPE_IPV4);
464 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800465 if (!supportTaggedMpls()) {
466 treatment.popVlan();
467 }
Charles Chan5270ed02016-01-30 23:22:37 -0800468 treatment.transition(UNICAST_ROUTING_TABLE);
469 FlowRule 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();
Charles Chan206506b2018-03-02 16:43:28 -0800477 return ImmutableList.of(ImmutableList.of(rule));
Charles Chan5270ed02016-01-30 23:22:37 -0800478 }
479
Saurav Das4ce45962015-11-24 23:21:05 -0800480 /*
481 * Cpqd emulation allows MPLS ecmp.
482 *
483 * (non-Javadoc)
484 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
485 */
486 @Override
487 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800488 TrafficSelector selector = fwd.selector();
489 EthTypeCriterion ethType =
490 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
491 if ((ethType == null) ||
492 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800493 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
494 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800495 log.warn("processSpecific: Unsupported forwarding objective criteria"
496 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800497 fail(fwd, ObjectiveError.UNSUPPORTED);
498 return Collections.emptySet();
499 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800500 boolean defaultRule = false;
Charles Chan93090352018-03-02 13:26:22 -0800501 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800502 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800503 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
504
Saurav Das8a0732e2015-11-20 15:27:53 -0800505 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800506 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700507 if (ipv4Dst.isMulticast()) {
508 if (ipv4Dst.prefixLength() != 32) {
509 log.warn("Multicast specific forwarding objective can only be /32");
510 fail(fwd, ObjectiveError.BADPARAMS);
511 return ImmutableSet.of();
512 }
513 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
514 if (assignedVlan == null) {
515 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
516 fail(fwd, ObjectiveError.BADPARAMS);
517 return ImmutableSet.of();
518 }
519 filteredSelector.matchVlanId(assignedVlan);
520 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
521 forTableId = MULTICAST_ROUTING_TABLE;
522 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
523 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800524 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700525 if (ipv4Dst.prefixLength() == 0) {
526 // The entire IPV4_DST field is wildcarded intentionally
527 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700528 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700529 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700530 }
531 forTableId = UNICAST_ROUTING_TABLE;
532 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
533 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800534 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800535 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
Julia Ferguson65428c32017-08-10 18:15:24 +0000536 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
537 if (ipv6Dst.isMulticast()) {
538 if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
539 log.debug("Multicast specific IPv6 forwarding objective can only be /128");
540 fail(fwd, ObjectiveError.BADPARAMS);
541 return ImmutableSet.of();
542 }
543 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
544 if (assignedVlan == null) {
545 log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
546 fail(fwd, ObjectiveError.BADPARAMS);
547 return ImmutableSet.of();
548 }
549 filteredSelector.matchVlanId(assignedVlan);
550 filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
551 forTableId = MULTICAST_ROUTING_TABLE;
552 log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
553 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
554 } else {
555 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
556 return Collections.emptyList();
557 }
558 forTableId = UNICAST_ROUTING_TABLE;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800559 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800560 } else {
561 filteredSelector
562 .matchEthType(Ethernet.MPLS_UNICAST)
563 .matchMplsLabel(((MplsCriterion)
564 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
565 MplsBosCriterion bos = (MplsBosCriterion) selector
566 .getCriterion(Criterion.Type.MPLS_BOS);
567 if (bos != null) {
568 filteredSelector.matchMplsBos(bos.mplsBos());
569 }
570 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800571 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
572 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800573 }
574
575 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
576 if (fwd.treatment() != null) {
577 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan40132b32017-01-22 00:19:37 -0800578 if (!supportCopyTtl() && i instanceof L3ModificationInstruction) {
579 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
580 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
581 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
582 continue;
583 }
584 }
Charles Chan7d10b162015-12-07 18:54:45 -0800585 /*
586 * NOTE: OF-DPA does not support immediate instruction in
587 * L3 unicast and MPLS table.
588 */
589 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800590 }
591 }
592
593 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800594 NextGroup next = getGroupForNextObjective(fwd.nextId());
595 if (next != null) {
596 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
597 // we only need the top level group's key to point the flow to it
598 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
599 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700600 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
601 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800602 fail(fwd, ObjectiveError.GROUPMISSING);
603 return Collections.emptySet();
604 }
605 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800606 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800607 }
608 tb.transition(ACL_TABLE);
609 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
610 .fromApp(fwd.appId())
611 .withPriority(fwd.priority())
612 .forDevice(deviceId)
613 .withSelector(filteredSelector.build())
614 .withTreatment(tb.build())
615 .forTable(forTableId);
616
617 if (fwd.permanent()) {
618 ruleBuilder.makePermanent();
619 } else {
620 ruleBuilder.makeTemporary(fwd.timeout());
621 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800622 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
623 flowRuleCollection.add(ruleBuilder.build());
624 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800625 flowRuleCollection.add(
626 defaultRoute(fwd, complementarySelector, forTableId, tb)
627 );
Flavio Castroe10fa242016-01-15 12:43:51 -0800628 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
629 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800630 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800631 }
632
Charles Chan1e492d32016-01-30 23:22:37 -0800633 @Override
634 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
635 List<FlowRule> rules = new ArrayList<>();
636
637 // Build filtered selector
638 TrafficSelector selector = fwd.selector();
639 EthCriterion ethCriterion = (EthCriterion) selector
640 .getCriterion(Criterion.Type.ETH_DST);
641 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
642 .getCriterion(Criterion.Type.VLAN_VID);
643
644 if (vlanIdCriterion == null) {
645 log.warn("Forwarding objective for bridging requires vlan. Not "
646 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
647 fail(fwd, ObjectiveError.BADPARAMS);
648 return Collections.emptySet();
649 }
650
651 TrafficSelector.Builder filteredSelectorBuilder =
652 DefaultTrafficSelector.builder();
653 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -0800654 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -0800655 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
656 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
657 fwd.id(), fwd.nextId(), deviceId);
658 } else {
659 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
660 + "in dev:{} for vlan:{}",
661 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
662 }
663 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
664 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
665
666 if (fwd.treatment() != null) {
667 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
668 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
669 }
670
671 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
672 if (fwd.nextId() != null) {
673 NextGroup next = getGroupForNextObjective(fwd.nextId());
674 if (next != null) {
675 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
676 // we only need the top level group's key to point the flow to it
677 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
678 if (group != null) {
679 treatmentBuilder.deferred().group(group.id());
680 } else {
681 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
682 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
683 fail(fwd, ObjectiveError.GROUPMISSING);
684 return Collections.emptySet();
685 }
686 }
687 }
688 treatmentBuilder.immediate().transition(ACL_TABLE);
689 TrafficTreatment filteredTreatment = treatmentBuilder.build();
690
691 // Build bridging table entries
692 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
693 flowRuleBuilder.fromApp(fwd.appId())
694 .withPriority(fwd.priority())
695 .forDevice(deviceId)
696 .withSelector(filteredSelector)
697 .withTreatment(filteredTreatment)
698 .forTable(BRIDGING_TABLE);
699 if (fwd.permanent()) {
700 flowRuleBuilder.makePermanent();
701 } else {
702 flowRuleBuilder.makeTemporary(fwd.timeout());
703 }
704 rules.add(flowRuleBuilder.build());
705 return rules;
706 }
707
Saurav Das52025962016-01-28 22:30:01 -0800708 /*
709 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
710 * ACL table. Because we pop off vlan tags in TMAC table,
711 * we need to avoid matching on vlans in the ACL table.
712 */
713 @Override
714 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
715 log.info("Processing versatile forwarding objective");
716
Saurav Das52025962016-01-28 22:30:01 -0800717 if (fwd.nextId() == null && fwd.treatment() == null) {
718 log.error("Forwarding objective {} from {} must contain "
719 + "nextId or Treatment", fwd.selector(), fwd.appId());
720 return Collections.emptySet();
721 }
722
723 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
724 fwd.selector().criteria().forEach(criterion -> {
725 if (criterion instanceof VlanIdCriterion) {
726 // avoid matching on vlans
727 return;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800728 } else if (criterion instanceof Icmpv6TypeCriterion ||
729 criterion instanceof Icmpv6CodeCriterion) {
730 /*
731 * We silenty discard these criterions, our current
732 * OFDPA platform does not support these matches on
733 * the ACL table.
734 */
735 log.warn("ICMPv6 Type and ICMPv6 Code are not supported");
Saurav Das52025962016-01-28 22:30:01 -0800736 } else {
737 sbuilder.add(criterion);
738 }
739 });
740
741 // XXX driver does not currently do type checking as per Tables 65-67 in
742 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
743 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
744 if (fwd.treatment() != null) {
745 for (Instruction ins : fwd.treatment().allInstructions()) {
746 if (ins instanceof OutputInstruction) {
747 OutputInstruction o = (OutputInstruction) ins;
748 if (o.port() == PortNumber.CONTROLLER) {
Charles Chan0f43e472017-02-14 14:00:16 -0800749 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -0800750 } else {
751 log.warn("Only allowed treatments in versatile forwarding "
752 + "objectives are punts to the controller");
753 }
Charles Chan3fe71712018-06-15 18:54:18 -0700754 } else if (ins instanceof NoActionInstruction) {
755 // No action is allowed and nothing needs to be done
Saurav Das52025962016-01-28 22:30:01 -0800756 } else {
757 log.warn("Cannot process instruction in versatile fwd {}", ins);
758 }
759 }
Charles Chan2df0e8a2017-01-09 11:45:08 -0800760 if (fwd.treatment().clearedDeferred()) {
761 ttBuilder.wipeDeferred();
762 }
Saurav Das52025962016-01-28 22:30:01 -0800763 }
764 if (fwd.nextId() != null) {
765 // overide case
766 NextGroup next = getGroupForNextObjective(fwd.nextId());
767 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
768 // we only need the top level group's key to point the flow to it
769 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
770 if (group == null) {
771 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
772 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
773 fail(fwd, ObjectiveError.GROUPMISSING);
774 return Collections.emptySet();
775 }
776 ttBuilder.deferred().group(group.id());
777 }
778
779 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
780 .fromApp(fwd.appId())
781 .withPriority(fwd.priority())
782 .forDevice(deviceId)
783 .withSelector(sbuilder.build())
784 .withTreatment(ttBuilder.build())
785 .makePermanent()
786 .forTable(ACL_TABLE);
787 return Collections.singletonList(ruleBuilder.build());
788 }
789
790 /*
791 * Cpqd emulation requires table-miss-entries in forwarding tables.
792 * Real OFDPA does not require these rules as they are put in by default.
793 *
794 * (non-Javadoc)
795 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
796 */
Saurav Das2857f382015-11-03 14:39:27 -0800797 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700798 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -0800799 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
800 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
801 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
802 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
803 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
804 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
805 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
806 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
807 initTableMiss(ACL_TABLE, -1, null);
Charles Chan0f43e472017-02-14 14:00:16 -0800808
809 if (supportPuntGroup()) {
810 initTableMiss(PUNT_TABLE, -1,
811 DefaultTrafficTreatment.builder().punt().build());
812 initPopVlanPuntGroup();
813 } else {
814 initTableMiss(PUNT_TABLE, -1,
815 DefaultTrafficTreatment.builder().popVlan().punt().build());
816 }
Saurav Das558afec2015-05-31 17:12:48 -0700817 }
818
Charles Chanf6ec1532017-02-08 16:10:40 -0800819 /**
820 * Install table-miss flow entry.
821 *
822 * If treatment exists, use it directly.
823 * Else if treatment does not exist but nextTable > 0, transit to next table.
824 * Else apply empty treatment.
825 *
826 * @param thisTable this table ID
827 * @param nextTable next table ID
828 * @param treatment traffic treatment to apply.
829 */
830 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -0700831 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -0800832 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -0700833
Charles Chanf6ec1532017-02-08 16:10:40 -0800834 if (treatment == null) {
835 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
836 if (nextTable > 0) {
837 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -0700838 }
Charles Chanf6ec1532017-02-08 16:10:40 -0800839 treatment = tBuilder.build();
840 }
Saurav Das558afec2015-05-31 17:12:48 -0700841
Charles Chanb7504392017-02-10 12:51:04 -0800842 FlowRule rule = DefaultFlowRule.builder()
843 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -0800844 .withSelector(selector)
845 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -0800846 .withPriority(LOWEST_PRIORITY)
847 .fromApp(driverId)
848 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -0800849 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -0800850 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -0800851
852 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
853 @Override
854 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800855 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800856 }
Saurav Das2857f382015-11-03 14:39:27 -0800857 @Override
858 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800859 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800860 }
861 }));
862 }
Charles Chan0f43e472017-02-14 14:00:16 -0800863
864 /**
865 * Builds a indirect group contains pop_vlan and punt actions.
866 * <p>
867 * Using group instead of immediate action to ensure that
868 * the copy of packet on the data plane is not affected by the pop vlan action.
869 */
870 private void initPopVlanPuntGroup() {
Yi Tsengef19de12017-04-24 11:33:05 -0700871 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -0800872 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
873 .popVlan().punt().build();
874 GroupBucket bucket =
875 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
876 GroupDescription groupDesc =
877 new DefaultGroupDescription(
878 deviceId,
879 GroupDescription.Type.INDIRECT,
880 new GroupBuckets(Collections.singletonList(bucket)),
881 groupKey,
882 POP_VLAN_PUNT_GROUP_ID,
883 driverId);
884 groupService.addGroup(groupDesc);
885
886 log.info("Initialized pop vlan punt group on {}", deviceId);
887 }
Yi Tsengef19de12017-04-24 11:33:05 -0700888
889 /**
890 * Generates group key for a static indirect group that pop vlan and punt to
891 * controller.
892 *
893 * @return the group key of the indirect table
894 */
895 private GroupKey popVlanPuntGroupKey() {
896 int hash = POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_BIT_MASK);
897 return new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(hash));
898 }
Andreas Pantelopoulos410d7302018-05-30 14:30:24 -0700899
900 private class PopVlanPuntGroupChecker implements Runnable {
901 @Override
902 public void run() {
903
904 Group group = groupService.getGroup(deviceId, popVlanPuntGroupKey());
905 if (group != null) {
906 // shutdown the executor
907 if (!groupChecker.isShutdown()) {
908 groupChecker.shutdown();
909 }
910 // if we have pending flow rules install them
911 if (flowRuleQueue.size() > 0) {
912 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
913 // we should not care about the context here, it can only be add
914 // since when removing the rules the group should be there already.
915 flowRuleQueue.forEach(ops::add);
916 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
917 @Override
918 public void onSuccess(FlowRuleOperations ops) {
919 log.debug("Applied {} pop vlan punt rules in device {}",
920 ops.stages().get(0).size(), deviceId);
921 }
922 @Override
923 public void onError(FlowRuleOperations ops) {
924 log.error("Failed to apply all pop vlan punt rules in dev {}", deviceId);
925 }
926 }));
927 }
928 }
929 }
930 }
Saurav Das558afec2015-05-31 17:12:48 -0700931}