blob: caee9a0e1b1c97a8e9dce5a7dcd084f9a7fd680a [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 Chan45b69ab2018-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;
Saurav Das2857f382015-11-03 14:39:27 -080027import org.onosproject.net.Port;
28import org.onosproject.net.PortNumber;
Saurav Das8a0732e2015-11-20 15:27:53 -080029import org.onosproject.net.behaviour.NextGroup;
Charles Chan425854b2016-04-11 15:32:12 -070030import org.onosproject.net.behaviour.PipelinerContext;
Saurav Das558afec2015-05-31 17:12:48 -070031import org.onosproject.net.flow.DefaultFlowRule;
32import org.onosproject.net.flow.DefaultTrafficSelector;
33import org.onosproject.net.flow.DefaultTrafficTreatment;
34import org.onosproject.net.flow.FlowRule;
35import org.onosproject.net.flow.FlowRuleOperations;
36import org.onosproject.net.flow.FlowRuleOperationsContext;
37import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
Saurav Das4ce45962015-11-24 23:21:05 -080039import org.onosproject.net.flow.criteria.Criteria;
Saurav Das8a0732e2015-11-20 15:27:53 -080040import org.onosproject.net.flow.criteria.Criterion;
Saurav Das4ce45962015-11-24 23:21:05 -080041import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080042import org.onosproject.net.flow.criteria.EthTypeCriterion;
43import org.onosproject.net.flow.criteria.IPCriterion;
Pier Ventree0ae7a32016-11-23 09:57:42 -080044import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion;
45import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080046import org.onosproject.net.flow.criteria.MplsBosCriterion;
47import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das2857f382015-11-03 14:39:27 -080048import org.onosproject.net.flow.criteria.PortCriterion;
49import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080050import org.onosproject.net.flow.instructions.Instruction;
Saurav Das52025962016-01-28 22:30:01 -080051import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Charles Chan40132b32017-01-22 00:19:37 -080052import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Saurav Das8a0732e2015-11-20 15:27:53 -080053import org.onosproject.net.flowobjective.ForwardingObjective;
54import org.onosproject.net.flowobjective.ObjectiveError;
Charles Chan0f43e472017-02-14 14:00:16 -080055import org.onosproject.net.group.DefaultGroupBucket;
56import org.onosproject.net.group.DefaultGroupDescription;
57import org.onosproject.net.group.DefaultGroupKey;
Saurav Das8a0732e2015-11-20 15:27:53 -080058import org.onosproject.net.group.Group;
Charles Chan0f43e472017-02-14 14:00:16 -080059import org.onosproject.net.group.GroupBucket;
60import org.onosproject.net.group.GroupBuckets;
61import org.onosproject.net.group.GroupDescription;
Saurav Das8a0732e2015-11-20 15:27:53 -080062import org.onosproject.net.group.GroupKey;
Charles Chanf57a8252016-06-29 19:12:37 -070063import org.onosproject.net.packet.PacketPriority;
Saurav Das558afec2015-05-31 17:12:48 -070064import org.slf4j.Logger;
65
Jonathan Hart855179c2016-04-26 07:40:04 -070066import java.util.ArrayList;
67import java.util.Collection;
68import java.util.Collections;
69import java.util.Deque;
70import java.util.List;
Charles Chan0f43e472017-02-14 14:00:16 -080071import java.util.Objects;
Jonathan Hart855179c2016-04-26 07:40:04 -070072
Pier Ventree0ae7a32016-11-23 09:57:42 -080073import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Charles Chand05f54b2017-02-13 11:56:54 -080074import static org.onlab.packet.MacAddress.BROADCAST;
75import static org.onlab.packet.MacAddress.NONE;
Yi Tsengef19de12017-04-24 11:33:05 -070076import static org.onosproject.driver.pipeline.ofdpa.OfdpaGroupHandlerUtility.*;
Jonathan Hart855179c2016-04-26 07:40:04 -070077import static org.slf4j.LoggerFactory.getLogger;
78
Saurav Das558afec2015-05-31 17:12:48 -070079
80/**
Charles Chan40132b32017-01-22 00:19:37 -080081 * Driver for software switch emulation of the OFDPA pipeline.
Saurav Das52025962016-01-28 22:30:01 -080082 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
83 * does not handle vlan tags and mpls labels simultaneously, which requires us
84 * to do some workarounds in the driver. This driver is meant for the use of
85 * the cpqd switch when MPLS is required. As a result this driver works only
86 * on incoming untagged packets.
Saurav Das558afec2015-05-31 17:12:48 -070087 */
Charles Chan361154b2016-03-24 10:23:39 -070088public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -070089
90 private final Logger log = getLogger(getClass());
91
Charles Chan40132b32017-01-22 00:19:37 -080092 /**
Charles Chan0f43e472017-02-14 14:00:16 -080093 * Table that determines whether VLAN is popped before punting to controller.
94 * <p>
95 * This is a non-OFDPA table to emulate OFDPA packet in behavior.
96 * VLAN will be popped before punting if the VLAN is internally assigned.
97 * <p>
98 * Also note that 63 is the max table number in CpqD.
99 */
100 private static final int PUNT_TABLE = 63;
101
102 /**
103 * A static indirect group that pop vlan and punt to controller.
104 * <p>
105 * The purpose of using a group instead of immediate action is that this
106 * won't affect another copy on the data plane when write action exists.
107 */
108 private static final int POP_VLAN_PUNT_GROUP_ID = 0xc0000000;
109
Charles Chan053b1cb2017-03-22 16:56:35 -0700110 @Override
111 protected boolean requireVlanExtensions() {
112 return false;
113 }
114
Charles Chan0f43e472017-02-14 14:00:16 -0800115 /**
Charles Chan40132b32017-01-22 00:19:37 -0800116 * Determines whether this pipeline support copy ttl instructions or not.
117 *
118 * @return true if copy ttl instructions are supported
119 */
120 protected boolean supportCopyTtl() {
121 return true;
122 }
123
Charles Chan0f43e472017-02-14 14:00:16 -0800124 /**
125 * Determines whether this pipeline support push mpls to vlan-tagged packets or not.
126 * <p>
127 * If not support, pop vlan before push entering unicast and mpls table.
128 * Side effect: HostService learns redundant hosts with same MAC but
129 * different VLAN. No known side effect on the network reachability.
130 *
131 * @return true if push mpls to vlan-tagged packets is supported
132 */
133 protected boolean supportTaggedMpls() {
134 return false;
135 }
136
137 /**
138 * Determines whether this pipeline support punt action in group bucket.
139 *
140 * @return true if punt action in group bucket is supported
141 */
142 protected boolean supportPuntGroup() {
143 return false;
144 }
145
Charles Chan425854b2016-04-11 15:32:12 -0700146 @Override
Charles Chan40132b32017-01-22 00:19:37 -0800147 protected void initDriverId() {
Charles Chan425854b2016-04-11 15:32:12 -0700148 driverId = coreService.registerApplication(
149 "org.onosproject.driver.CpqdOfdpa2Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -0800150 }
Charles Chan425854b2016-04-11 15:32:12 -0700151
Charles Chan40132b32017-01-22 00:19:37 -0800152 @Override
153 protected void initGroupHander(PipelinerContext context) {
154 groupHandler = new CpqdOfdpa2GroupHandler();
155 groupHandler.init(deviceId, context);
Charles Chan425854b2016-04-11 15:32:12 -0700156 }
157
Saurav Das4ce45962015-11-24 23:21:05 -0800158 /*
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700159 * Cpqd emulation does not require the non OF-standard rules for
160 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800161 *
162 * (non-Javadoc)
163 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
164 */
Saurav Das558afec2015-05-31 17:12:48 -0700165 @Override
Charles Chan66291502018-03-02 16:43:28 -0800166 protected List<List<FlowRule>> processVlanIdFilter(PortCriterion portCriterion,
Saurav Das2857f382015-11-03 14:39:27 -0800167 VlanIdCriterion vidCriterion,
168 VlanId assignedVlan,
169 ApplicationId applicationId) {
Charles Chan79769232016-07-05 16:34:39 -0700170 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800171 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
172 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
173 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800174 treatment.transition(TMAC_TABLE);
175
Saurav Das2857f382015-11-03 14:39:27 -0800176 if (vidCriterion.vlanId() == VlanId.NONE) {
177 // untagged packets are assigned vlans
178 treatment.pushVlan().setVlanId(assignedVlan);
Piere5bff482018-03-07 11:42:50 +0100179 } else if (!vidCriterion.vlanId().equals(assignedVlan)) {
180 // Rewrite with assigned vlans
181 treatment.setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800182 }
Saurav Das2857f382015-11-03 14:39:27 -0800183
184 // ofdpa cannot match on ALL portnumber, so we need to use separate
185 // rules for each port.
Charles Chan50d900c2018-03-02 13:26:22 -0800186 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeybe9f3bc2018-05-10 12:42:51 -0700187 if (portCriterion != null) {
188 if (portCriterion.port() == PortNumber.ALL) {
189 for (Port port : deviceService.getPorts(deviceId)) {
190 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
191 portnums.add(port.number());
192 }
Saurav Das2857f382015-11-03 14:39:27 -0800193 }
Ray Milkeybe9f3bc2018-05-10 12:42:51 -0700194 } else {
195 portnums.add(portCriterion.port());
Saurav Das2857f382015-11-03 14:39:27 -0800196 }
Saurav Das2857f382015-11-03 14:39:27 -0800197 }
Saurav Das4f980082015-11-05 13:39:15 -0800198
Saurav Das2857f382015-11-03 14:39:27 -0800199 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800200 // NOTE: Emulating OFDPA behavior by popping off internal assigned
201 // VLAN before sending to controller
202 if (supportPuntGroup() && vidCriterion.vlanId() == VlanId.NONE) {
Yi Tsengef19de12017-04-24 11:33:05 -0700203 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -0800204 Group group = groupService.getGroup(deviceId, groupKey);
205 if (group != null) {
206 rules.add(buildPuntTableRule(pnum, assignedVlan));
207 } else {
208 log.info("popVlanPuntGroup not found in dev:{}", deviceId);
209 return Collections.emptyList();
210 }
211 }
212
Saurav Das4f980082015-11-05 13:39:15 -0800213 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800214 selector.matchInPort(pnum);
215 FlowRule rule = DefaultFlowRule.builder()
216 .forDevice(deviceId)
217 .withSelector(selector.build())
218 .withTreatment(treatment.build())
219 .withPriority(DEFAULT_PRIORITY)
220 .fromApp(applicationId)
221 .makePermanent()
222 .forTable(VLAN_TABLE).build();
223 rules.add(rule);
224 }
Charles Chanf57a8252016-06-29 19:12:37 -0700225
Charles Chan66291502018-03-02 16:43:28 -0800226 return ImmutableList.of(rules);
Saurav Das2857f382015-11-03 14:39:27 -0800227 }
228
Pier Ventree0ae7a32016-11-23 09:57:42 -0800229 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800230 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
231 * a group that pop vlan and punt.
232 *
233 * @param portNumber port number
234 * @param assignedVlan internally assigned vlan id
235 * @return punt table flow rule
236 */
237 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
238 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
239 .matchInPort(portNumber)
240 .matchVlanId(assignedVlan);
241 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
Yi Tsengfa394de2017-02-01 11:26:40 -0800242 .group(new GroupId(POP_VLAN_PUNT_GROUP_ID));
Charles Chan0f43e472017-02-14 14:00:16 -0800243
244 return DefaultFlowRule.builder()
245 .forDevice(deviceId)
246 .withSelector(sbuilder.build())
247 .withTreatment(tbuilder.build())
248 .withPriority(PacketPriority.CONTROL.priorityValue())
249 .fromApp(driverId)
250 .makePermanent()
251 .forTable(PUNT_TABLE).build();
252 }
253
254 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800255 * Builds a punt to the controller rule for the arp protocol.
Charles Chan0f43e472017-02-14 14:00:16 -0800256 * <p>
257 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
258 * pop VLAN before sending to controller disregarding whether
259 * it's an internally assigned VLAN or a natural VLAN.
260 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800261 *
262 * @param assignedVlan the internal assigned vlan id
263 * @param applicationId the application id
264 * @return the punt flow rule for the arp
265 */
266 private FlowRule buildArpPunt(VlanId assignedVlan, ApplicationId applicationId) {
267 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
268 .matchEthType(Ethernet.TYPE_ARP)
269 .matchVlanId(assignedVlan);
270 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
271 .popVlan()
272 .punt();
273
274 return DefaultFlowRule.builder()
275 .forDevice(deviceId)
276 .withSelector(sbuilder.build())
277 .withTreatment(tbuilder.build())
278 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
279 .fromApp(applicationId)
280 .makePermanent()
281 .forTable(ACL_TABLE).build();
282 }
283
284 /**
285 * Builds a punt to the controller rule for the icmp v6 messages.
Charles Chan0f43e472017-02-14 14:00:16 -0800286 * <p>
287 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
288 * pop VLAN before sending to controller disregarding whether
289 * it's an internally assigned VLAN or a natural VLAN.
290 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800291 *
292 * @param assignedVlan the internal assigned vlan id
293 * @param applicationId the application id
294 * @return the punt flow rule for the icmp v6 messages
295 */
296 private FlowRule buildIcmpV6Punt(VlanId assignedVlan, ApplicationId applicationId) {
297 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
298 .matchVlanId(assignedVlan)
299 .matchEthType(Ethernet.TYPE_IPV6)
300 .matchIPProtocol(PROTOCOL_ICMP6);
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
Saurav Das4ce45962015-11-24 23:21:05 -0800315 /*
316 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
317 * Workaround requires popping off the VLAN tags in the TMAC table.
318 *
319 * (non-Javadoc)
320 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
321 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800322 @Override
Charles Chan66291502018-03-02 16:43:28 -0800323 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das4ce45962015-11-24 23:21:05 -0800324 EthCriterion ethCriterion,
325 VlanIdCriterion vidCriterion,
326 VlanId assignedVlan,
Charles Chan45b69ab2018-03-02 15:41:41 -0800327 MacAddress unicastMac,
Saurav Das4ce45962015-11-24 23:21:05 -0800328 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800329 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
330 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
331 return processEthDstOnlyFilter(ethCriterion, applicationId);
332 }
333
Charles Chan5b9df8d2016-03-28 22:21:40 -0700334 // Multicast MAC
335 if (ethCriterion.mask() != null) {
Charles Chan45b69ab2018-03-02 15:41:41 -0800336 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700337 }
338
Saurav Das4ce45962015-11-24 23:21:05 -0800339 //handling untagged packets via assigned VLAN
340 if (vidCriterion.vlanId() == VlanId.NONE) {
341 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
342 }
343 // ofdpa cannot match on ALL portnumber, so we need to use separate
344 // rules for each port.
Charles Chan50d900c2018-03-02 13:26:22 -0800345 List<PortNumber> portnums = new ArrayList<>();
Ray Milkey74e59132018-01-17 15:24:52 -0800346 if (portCriterion != null) {
347 if (portCriterion.port() == PortNumber.ALL) {
348 for (Port port : deviceService.getPorts(deviceId)) {
349 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
350 portnums.add(port.number());
351 }
Saurav Das4ce45962015-11-24 23:21:05 -0800352 }
Ray Milkey74e59132018-01-17 15:24:52 -0800353 } else {
354 portnums.add(portCriterion.port());
Saurav Das4ce45962015-11-24 23:21:05 -0800355 }
Saurav Das4ce45962015-11-24 23:21:05 -0800356 }
357
Charles Chan50d900c2018-03-02 13:26:22 -0800358 List<FlowRule> rules = new ArrayList<>();
Saurav Das4ce45962015-11-24 23:21:05 -0800359 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800360 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800361 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
362 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
363 selector.matchInPort(pnum);
364 selector.matchVlanId(vidCriterion.vlanId());
365 selector.matchEthType(Ethernet.TYPE_IPV4);
366 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800367 if (!supportTaggedMpls()) {
368 treatment.popVlan();
369 }
Saurav Das4ce45962015-11-24 23:21:05 -0800370 treatment.transition(UNICAST_ROUTING_TABLE);
371 FlowRule rule = DefaultFlowRule.builder()
372 .forDevice(deviceId)
373 .withSelector(selector.build())
374 .withTreatment(treatment.build())
375 .withPriority(DEFAULT_PRIORITY)
376 .fromApp(applicationId)
377 .makePermanent()
378 .forTable(TMAC_TABLE).build();
379 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800380
381 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800382 selector = DefaultTrafficSelector.builder();
383 treatment = DefaultTrafficTreatment.builder();
384 selector.matchInPort(pnum);
385 selector.matchVlanId(vidCriterion.vlanId());
386 selector.matchEthType(Ethernet.MPLS_UNICAST);
387 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800388 if (!supportTaggedMpls()) {
389 treatment.popVlan();
390 }
Saurav Das4ce45962015-11-24 23:21:05 -0800391 treatment.transition(MPLS_TABLE_0);
392 rule = DefaultFlowRule.builder()
393 .forDevice(deviceId)
394 .withSelector(selector.build())
395 .withTreatment(treatment.build())
396 .withPriority(DEFAULT_PRIORITY)
397 .fromApp(applicationId)
398 .makePermanent()
399 .forTable(TMAC_TABLE).build();
400 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800401
402 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800403 selector = DefaultTrafficSelector.builder();
404 treatment = DefaultTrafficTreatment.builder();
405 selector.matchInPort(pnum);
406 selector.matchVlanId(vidCriterion.vlanId());
407 selector.matchEthType(Ethernet.TYPE_IPV6);
408 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800409 if (!supportTaggedMpls()) {
410 treatment.popVlan();
411 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800412 treatment.transition(UNICAST_ROUTING_TABLE);
413 rule = DefaultFlowRule.builder()
414 .forDevice(deviceId)
415 .withSelector(selector.build())
416 .withTreatment(treatment.build())
417 .withPriority(DEFAULT_PRIORITY)
418 .fromApp(applicationId)
419 .makePermanent()
420 .forTable(TMAC_TABLE).build();
421 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800422 }
Charles Chan66291502018-03-02 16:43:28 -0800423 return ImmutableList.of(rules);
Saurav Das4ce45962015-11-24 23:21:05 -0800424 }
425
Charles Chan5270ed02016-01-30 23:22:37 -0800426 @Override
Charles Chan66291502018-03-02 16:43:28 -0800427 protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700428 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800429 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
430 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
431 selector.matchEthType(Ethernet.TYPE_IPV4);
432 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800433 if (!supportTaggedMpls()) {
434 treatment.popVlan();
435 }
Charles Chan5270ed02016-01-30 23:22:37 -0800436 treatment.transition(UNICAST_ROUTING_TABLE);
437 FlowRule rule = DefaultFlowRule.builder()
438 .forDevice(deviceId)
439 .withSelector(selector.build())
440 .withTreatment(treatment.build())
441 .withPriority(DEFAULT_PRIORITY)
442 .fromApp(applicationId)
443 .makePermanent()
444 .forTable(TMAC_TABLE).build();
Charles Chan66291502018-03-02 16:43:28 -0800445 return ImmutableList.of(ImmutableList.of(rule));
Charles Chan5270ed02016-01-30 23:22:37 -0800446 }
447
Saurav Das4ce45962015-11-24 23:21:05 -0800448 /*
449 * Cpqd emulation allows MPLS ecmp.
450 *
451 * (non-Javadoc)
452 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
453 */
454 @Override
455 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800456 TrafficSelector selector = fwd.selector();
457 EthTypeCriterion ethType =
458 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
459 if ((ethType == null) ||
460 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800461 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
462 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800463 log.warn("processSpecific: Unsupported forwarding objective criteria"
464 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800465 fail(fwd, ObjectiveError.UNSUPPORTED);
466 return Collections.emptySet();
467 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800468 boolean defaultRule = false;
Charles Chan50d900c2018-03-02 13:26:22 -0800469 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800470 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800471 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
472
Saurav Das8a0732e2015-11-20 15:27:53 -0800473 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800474 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700475 if (ipv4Dst.isMulticast()) {
476 if (ipv4Dst.prefixLength() != 32) {
477 log.warn("Multicast specific forwarding objective can only be /32");
478 fail(fwd, ObjectiveError.BADPARAMS);
479 return ImmutableSet.of();
480 }
481 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
482 if (assignedVlan == null) {
483 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
484 fail(fwd, ObjectiveError.BADPARAMS);
485 return ImmutableSet.of();
486 }
487 filteredSelector.matchVlanId(assignedVlan);
488 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
489 forTableId = MULTICAST_ROUTING_TABLE;
490 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
491 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800492 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700493 if (ipv4Dst.prefixLength() == 0) {
494 // The entire IPV4_DST field is wildcarded intentionally
495 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700496 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700497 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700498 }
499 forTableId = UNICAST_ROUTING_TABLE;
500 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
501 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800502 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800503 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
Julia Ferguson65428c32017-08-10 18:15:24 +0000504 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
505 if (ipv6Dst.isMulticast()) {
506 if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
507 log.debug("Multicast specific IPv6 forwarding objective can only be /128");
508 fail(fwd, ObjectiveError.BADPARAMS);
509 return ImmutableSet.of();
510 }
511 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
512 if (assignedVlan == null) {
513 log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
514 fail(fwd, ObjectiveError.BADPARAMS);
515 return ImmutableSet.of();
516 }
517 filteredSelector.matchVlanId(assignedVlan);
518 filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
519 forTableId = MULTICAST_ROUTING_TABLE;
520 log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
521 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
522 } else {
523 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
524 return Collections.emptyList();
525 }
526 forTableId = UNICAST_ROUTING_TABLE;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800527 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800528 } else {
529 filteredSelector
530 .matchEthType(Ethernet.MPLS_UNICAST)
531 .matchMplsLabel(((MplsCriterion)
532 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
533 MplsBosCriterion bos = (MplsBosCriterion) selector
534 .getCriterion(Criterion.Type.MPLS_BOS);
535 if (bos != null) {
536 filteredSelector.matchMplsBos(bos.mplsBos());
537 }
538 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800539 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
540 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800541 }
542
543 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
544 if (fwd.treatment() != null) {
545 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan40132b32017-01-22 00:19:37 -0800546 if (!supportCopyTtl() && i instanceof L3ModificationInstruction) {
547 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
548 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
549 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
550 continue;
551 }
552 }
Charles Chan7d10b162015-12-07 18:54:45 -0800553 /*
554 * NOTE: OF-DPA does not support immediate instruction in
555 * L3 unicast and MPLS table.
556 */
557 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800558 }
559 }
560
561 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800562 NextGroup next = getGroupForNextObjective(fwd.nextId());
563 if (next != null) {
564 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
565 // we only need the top level group's key to point the flow to it
566 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
567 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700568 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
569 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800570 fail(fwd, ObjectiveError.GROUPMISSING);
571 return Collections.emptySet();
572 }
573 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800574 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800575 }
576 tb.transition(ACL_TABLE);
577 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
578 .fromApp(fwd.appId())
579 .withPriority(fwd.priority())
580 .forDevice(deviceId)
581 .withSelector(filteredSelector.build())
582 .withTreatment(tb.build())
583 .forTable(forTableId);
584
585 if (fwd.permanent()) {
586 ruleBuilder.makePermanent();
587 } else {
588 ruleBuilder.makeTemporary(fwd.timeout());
589 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800590 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
591 flowRuleCollection.add(ruleBuilder.build());
592 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800593 flowRuleCollection.add(
594 defaultRoute(fwd, complementarySelector, forTableId, tb)
595 );
Flavio Castroe10fa242016-01-15 12:43:51 -0800596 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
597 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800598 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800599 }
600
Charles Chan1e492d32016-01-30 23:22:37 -0800601 @Override
602 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
603 List<FlowRule> rules = new ArrayList<>();
604
605 // Build filtered selector
606 TrafficSelector selector = fwd.selector();
607 EthCriterion ethCriterion = (EthCriterion) selector
608 .getCriterion(Criterion.Type.ETH_DST);
609 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
610 .getCriterion(Criterion.Type.VLAN_VID);
611
612 if (vlanIdCriterion == null) {
613 log.warn("Forwarding objective for bridging requires vlan. Not "
614 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
615 fail(fwd, ObjectiveError.BADPARAMS);
616 return Collections.emptySet();
617 }
618
619 TrafficSelector.Builder filteredSelectorBuilder =
620 DefaultTrafficSelector.builder();
621 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -0800622 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -0800623 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
624 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
625 fwd.id(), fwd.nextId(), deviceId);
626 } else {
627 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
628 + "in dev:{} for vlan:{}",
629 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
630 }
631 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
632 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
633
634 if (fwd.treatment() != null) {
635 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
636 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
637 }
638
639 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
640 if (fwd.nextId() != null) {
641 NextGroup next = getGroupForNextObjective(fwd.nextId());
642 if (next != null) {
643 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
644 // we only need the top level group's key to point the flow to it
645 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
646 if (group != null) {
647 treatmentBuilder.deferred().group(group.id());
648 } else {
649 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
650 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
651 fail(fwd, ObjectiveError.GROUPMISSING);
652 return Collections.emptySet();
653 }
654 }
655 }
656 treatmentBuilder.immediate().transition(ACL_TABLE);
657 TrafficTreatment filteredTreatment = treatmentBuilder.build();
658
659 // Build bridging table entries
660 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
661 flowRuleBuilder.fromApp(fwd.appId())
662 .withPriority(fwd.priority())
663 .forDevice(deviceId)
664 .withSelector(filteredSelector)
665 .withTreatment(filteredTreatment)
666 .forTable(BRIDGING_TABLE);
667 if (fwd.permanent()) {
668 flowRuleBuilder.makePermanent();
669 } else {
670 flowRuleBuilder.makeTemporary(fwd.timeout());
671 }
672 rules.add(flowRuleBuilder.build());
673 return rules;
674 }
675
Saurav Das52025962016-01-28 22:30:01 -0800676 /*
677 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
678 * ACL table. Because we pop off vlan tags in TMAC table,
679 * we need to avoid matching on vlans in the ACL table.
680 */
681 @Override
682 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
683 log.info("Processing versatile forwarding objective");
684
685 EthTypeCriterion ethType =
686 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
687 if (ethType == null) {
688 log.error("Versatile forwarding objective must include ethType");
689 fail(fwd, ObjectiveError.BADPARAMS);
690 return Collections.emptySet();
691 }
692 if (fwd.nextId() == null && fwd.treatment() == null) {
693 log.error("Forwarding objective {} from {} must contain "
694 + "nextId or Treatment", fwd.selector(), fwd.appId());
695 return Collections.emptySet();
696 }
697
698 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
699 fwd.selector().criteria().forEach(criterion -> {
700 if (criterion instanceof VlanIdCriterion) {
701 // avoid matching on vlans
702 return;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800703 } else if (criterion instanceof Icmpv6TypeCriterion ||
704 criterion instanceof Icmpv6CodeCriterion) {
705 /*
706 * We silenty discard these criterions, our current
707 * OFDPA platform does not support these matches on
708 * the ACL table.
709 */
710 log.warn("ICMPv6 Type and ICMPv6 Code are not supported");
Saurav Das52025962016-01-28 22:30:01 -0800711 } else {
712 sbuilder.add(criterion);
713 }
714 });
715
716 // XXX driver does not currently do type checking as per Tables 65-67 in
717 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
718 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
719 if (fwd.treatment() != null) {
720 for (Instruction ins : fwd.treatment().allInstructions()) {
721 if (ins instanceof OutputInstruction) {
722 OutputInstruction o = (OutputInstruction) ins;
723 if (o.port() == PortNumber.CONTROLLER) {
Charles Chan0f43e472017-02-14 14:00:16 -0800724 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -0800725 } else {
726 log.warn("Only allowed treatments in versatile forwarding "
727 + "objectives are punts to the controller");
728 }
729 } else {
730 log.warn("Cannot process instruction in versatile fwd {}", ins);
731 }
732 }
Charles Chan2df0e8a2017-01-09 11:45:08 -0800733 if (fwd.treatment().clearedDeferred()) {
734 ttBuilder.wipeDeferred();
735 }
Saurav Das52025962016-01-28 22:30:01 -0800736 }
737 if (fwd.nextId() != null) {
738 // overide case
739 NextGroup next = getGroupForNextObjective(fwd.nextId());
740 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
741 // we only need the top level group's key to point the flow to it
742 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
743 if (group == null) {
744 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
745 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
746 fail(fwd, ObjectiveError.GROUPMISSING);
747 return Collections.emptySet();
748 }
749 ttBuilder.deferred().group(group.id());
750 }
751
752 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
753 .fromApp(fwd.appId())
754 .withPriority(fwd.priority())
755 .forDevice(deviceId)
756 .withSelector(sbuilder.build())
757 .withTreatment(ttBuilder.build())
758 .makePermanent()
759 .forTable(ACL_TABLE);
760 return Collections.singletonList(ruleBuilder.build());
761 }
762
763 /*
764 * Cpqd emulation requires table-miss-entries in forwarding tables.
765 * Real OFDPA does not require these rules as they are put in by default.
766 *
767 * (non-Javadoc)
768 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
769 */
Saurav Das2857f382015-11-03 14:39:27 -0800770 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700771 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -0800772 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
773 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
774 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
775 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
776 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
777 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
778 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
779 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
780 initTableMiss(ACL_TABLE, -1, null);
Charles Chan0f43e472017-02-14 14:00:16 -0800781
782 if (supportPuntGroup()) {
783 initTableMiss(PUNT_TABLE, -1,
784 DefaultTrafficTreatment.builder().punt().build());
785 initPopVlanPuntGroup();
786 } else {
787 initTableMiss(PUNT_TABLE, -1,
788 DefaultTrafficTreatment.builder().popVlan().punt().build());
789 }
Saurav Das558afec2015-05-31 17:12:48 -0700790 }
791
Charles Chanf6ec1532017-02-08 16:10:40 -0800792 /**
793 * Install table-miss flow entry.
794 *
795 * If treatment exists, use it directly.
796 * Else if treatment does not exist but nextTable > 0, transit to next table.
797 * Else apply empty treatment.
798 *
799 * @param thisTable this table ID
800 * @param nextTable next table ID
801 * @param treatment traffic treatment to apply.
802 */
803 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -0700804 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -0800805 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -0700806
Charles Chanf6ec1532017-02-08 16:10:40 -0800807 if (treatment == null) {
808 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
809 if (nextTable > 0) {
810 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -0700811 }
Charles Chanf6ec1532017-02-08 16:10:40 -0800812 treatment = tBuilder.build();
813 }
Saurav Das558afec2015-05-31 17:12:48 -0700814
Charles Chanb7504392017-02-10 12:51:04 -0800815 FlowRule rule = DefaultFlowRule.builder()
816 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -0800817 .withSelector(selector)
818 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -0800819 .withPriority(LOWEST_PRIORITY)
820 .fromApp(driverId)
821 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -0800822 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -0800823 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -0800824
825 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
826 @Override
827 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800828 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800829 }
Saurav Das2857f382015-11-03 14:39:27 -0800830 @Override
831 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800832 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800833 }
834 }));
835 }
Charles Chan0f43e472017-02-14 14:00:16 -0800836
837 /**
838 * Builds a indirect group contains pop_vlan and punt actions.
839 * <p>
840 * Using group instead of immediate action to ensure that
841 * the copy of packet on the data plane is not affected by the pop vlan action.
842 */
843 private void initPopVlanPuntGroup() {
Yi Tsengef19de12017-04-24 11:33:05 -0700844 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -0800845 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
846 .popVlan().punt().build();
847 GroupBucket bucket =
848 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
849 GroupDescription groupDesc =
850 new DefaultGroupDescription(
851 deviceId,
852 GroupDescription.Type.INDIRECT,
853 new GroupBuckets(Collections.singletonList(bucket)),
854 groupKey,
855 POP_VLAN_PUNT_GROUP_ID,
856 driverId);
857 groupService.addGroup(groupDesc);
858
859 log.info("Initialized pop vlan punt group on {}", deviceId);
860 }
Yi Tsengef19de12017-04-24 11:33:05 -0700861
862 /**
863 * Generates group key for a static indirect group that pop vlan and punt to
864 * controller.
865 *
866 * @return the group key of the indirect table
867 */
868 private GroupKey popVlanPuntGroupKey() {
869 int hash = POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_BIT_MASK);
870 return new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(hash));
871 }
Saurav Das558afec2015-05-31 17:12:48 -0700872}