blob: 0d79dcdd3471f7e22c3aa4af8adb90b96b6c26ba [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Thomas Vachuska58de4162015-09-10 16:15:33 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Yi Tsengef19de12017-04-24 11:33:05 -070016package org.onosproject.driver.pipeline.ofdpa;
Saurav Das558afec2015-05-31 17:12:48 -070017
Charles Chan5270ed02016-01-30 23:22:37 -080018import com.google.common.collect.ImmutableList;
Charles Chan5b9df8d2016-03-28 22:21:40 -070019import com.google.common.collect.ImmutableSet;
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -070020import org.onlab.packet.EthType;
Saurav Das8a0732e2015-11-20 15:27:53 -080021import org.onlab.packet.Ethernet;
Julia Ferguson65428c32017-08-10 18:15:24 +000022import org.onlab.packet.IpAddress;
Flavio Castroe10fa242016-01-15 12:43:51 -080023import org.onlab.packet.IpPrefix;
Charles Chan45b69ab2018-03-02 15:41:41 -080024import org.onlab.packet.MacAddress;
Saurav Das2857f382015-11-03 14:39:27 -080025import org.onlab.packet.VlanId;
26import org.onosproject.core.ApplicationId;
Yi Tsengfa394de2017-02-01 11:26:40 -080027import org.onosproject.core.GroupId;
Andrea Campanella7c977b92018-05-30 21:39:45 -070028import org.onosproject.net.ConnectPoint;
Andreas Pantelopoulos89369462018-05-30 14:30:24 -070029import org.onosproject.net.DeviceId;
Andrea Campanella7c977b92018-05-30 21:39:45 -070030import org.onosproject.driver.extensions.OfdpaMatchActsetOutput;
31import org.onosproject.net.Host;
Saurav Das2857f382015-11-03 14:39:27 -080032import org.onosproject.net.Port;
33import org.onosproject.net.PortNumber;
Saurav Das8a0732e2015-11-20 15:27:53 -080034import org.onosproject.net.behaviour.NextGroup;
Charles Chan425854b2016-04-11 15:32:12 -070035import org.onosproject.net.behaviour.PipelinerContext;
Saurav Das558afec2015-05-31 17:12:48 -070036import org.onosproject.net.flow.DefaultFlowRule;
37import org.onosproject.net.flow.DefaultTrafficSelector;
38import org.onosproject.net.flow.DefaultTrafficTreatment;
39import org.onosproject.net.flow.FlowRule;
40import org.onosproject.net.flow.FlowRuleOperations;
41import org.onosproject.net.flow.FlowRuleOperationsContext;
42import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
Saurav Das4ce45962015-11-24 23:21:05 -080044import org.onosproject.net.flow.criteria.Criteria;
Saurav Das8a0732e2015-11-20 15:27:53 -080045import org.onosproject.net.flow.criteria.Criterion;
Saurav Das4ce45962015-11-24 23:21:05 -080046import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080047import org.onosproject.net.flow.criteria.EthTypeCriterion;
48import org.onosproject.net.flow.criteria.IPCriterion;
49import org.onosproject.net.flow.criteria.MplsBosCriterion;
50import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das2857f382015-11-03 14:39:27 -080051import org.onosproject.net.flow.criteria.PortCriterion;
52import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080053import org.onosproject.net.flow.instructions.Instruction;
Andrea Campanella7c977b92018-05-30 21:39:45 -070054import org.onosproject.net.flow.instructions.Instructions;
Saurav Das52025962016-01-28 22:30:01 -080055import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Charles Chanf76de302018-06-15 18:54:18 -070056import org.onosproject.net.flow.instructions.Instructions.NoActionInstruction;
Andrea Campanella7c977b92018-05-30 21:39:45 -070057import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Charles Chan40132b32017-01-22 00:19:37 -080058import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Andrea Campanella7c977b92018-05-30 21:39:45 -070059import org.onosproject.net.flowobjective.FilteringObjective;
Saurav Das8a0732e2015-11-20 15:27:53 -080060import org.onosproject.net.flowobjective.ForwardingObjective;
61import org.onosproject.net.flowobjective.ObjectiveError;
Charles Chan0f43e472017-02-14 14:00:16 -080062import org.onosproject.net.group.DefaultGroupBucket;
63import org.onosproject.net.group.DefaultGroupDescription;
64import org.onosproject.net.group.DefaultGroupKey;
Saurav Das8a0732e2015-11-20 15:27:53 -080065import org.onosproject.net.group.Group;
Charles Chan0f43e472017-02-14 14:00:16 -080066import org.onosproject.net.group.GroupBucket;
67import org.onosproject.net.group.GroupBuckets;
68import org.onosproject.net.group.GroupDescription;
Saurav Das8a0732e2015-11-20 15:27:53 -080069import org.onosproject.net.group.GroupKey;
Andrea Campanella7c977b92018-05-30 21:39:45 -070070import org.onosproject.net.host.HostService;
Charles Chanf57a8252016-06-29 19:12:37 -070071import org.onosproject.net.packet.PacketPriority;
Saurav Das558afec2015-05-31 17:12:48 -070072import org.slf4j.Logger;
73
Jonathan Hart855179c2016-04-26 07:40:04 -070074import java.util.ArrayList;
75import java.util.Collection;
76import java.util.Collections;
77import java.util.Deque;
Andrea Campanella7c977b92018-05-30 21:39:45 -070078import java.util.HashSet;
Jonathan Hart855179c2016-04-26 07:40:04 -070079import java.util.List;
Charles Chan0f43e472017-02-14 14:00:16 -080080import java.util.Objects;
Andreas Pantelopoulos89369462018-05-30 14:30:24 -070081import java.util.Queue;
82import java.util.concurrent.ConcurrentLinkedQueue;
83import java.util.concurrent.Executors;
84import java.util.concurrent.ScheduledExecutorService;
85import java.util.concurrent.TimeUnit;
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -070086import java.util.concurrent.locks.ReentrantLock;
Andrea Campanella7c977b92018-05-30 21:39:45 -070087import java.util.Optional;
Jonathan Hart855179c2016-04-26 07:40:04 -070088
Charles Chand05f54b2017-02-13 11:56:54 -080089import static org.onlab.packet.MacAddress.BROADCAST;
90import static org.onlab.packet.MacAddress.NONE;
Andreas Pantelopoulos89369462018-05-30 14:30:24 -070091import static org.onlab.util.Tools.groupedThreads;
Yi Tsengef19de12017-04-24 11:33:05 -070092import static org.onosproject.driver.pipeline.ofdpa.OfdpaGroupHandlerUtility.*;
pier9469f3e2019-04-17 17:05:08 +020093import static org.onosproject.driver.pipeline.ofdpa.OfdpaPipelineUtility.*;
Andrea Campanella7c977b92018-05-30 21:39:45 -070094import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
Jonathan Hart855179c2016-04-26 07:40:04 -070095import static org.slf4j.LoggerFactory.getLogger;
96
Saurav Das558afec2015-05-31 17:12:48 -070097/**
Charles Chanab591602019-01-22 17:25:04 -080098 * Driver for Open vSwitch emulation of the OFDPA pipeline.
Saurav Das558afec2015-05-31 17:12:48 -070099 */
Charles Chanab591602019-01-22 17:25:04 -0800100public class OvsOfdpaPipeline extends Ofdpa2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -0700101
102 private final Logger log = getLogger(getClass());
103
Andrea Campanella7c977b92018-05-30 21:39:45 -0700104 private static final int EGRESS_VLAN_FLOW_TABLE_IN_INGRESS = 31;
105 private static final int UNICAST_ROUTING_TABLE_1 = 32;
Charles Chan40132b32017-01-22 00:19:37 -0800106 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800107 * Table that determines whether VLAN is popped before punting to controller.
108 * <p>
109 * This is a non-OFDPA table to emulate OFDPA packet in behavior.
110 * VLAN will be popped before punting if the VLAN is internally assigned.
Charles Chan0f43e472017-02-14 14:00:16 -0800111 */
pierventreb58e9c92020-05-22 09:42:31 -0700112 public static final int PUNT_TABLE = 63;
Charles Chan0f43e472017-02-14 14:00:16 -0800113
114 /**
115 * A static indirect group that pop vlan and punt to controller.
116 * <p>
117 * The purpose of using a group instead of immediate action is that this
118 * won't affect another copy on the data plane when write action exists.
119 */
pierventreb58e9c92020-05-22 09:42:31 -0700120 public static final int POP_VLAN_PUNT_GROUP_ID = 0xd0000000;
Charles Chan0f43e472017-02-14 14:00:16 -0800121
Andreas Pantelopoulos89369462018-05-30 14:30:24 -0700122 /**
123 * Executor for group checker thread that checks pop vlan punt group.
124 */
125 private ScheduledExecutorService groupChecker;
126
127 /**
128 * Queue for passing pop vlan punt group flow rules to the GroupChecker thread.
129 */
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700130 private Queue<FlowRule> flowRuleQueue;
131
132 /**
133 * Lock used in synchronizing driver thread with groupCheckerThread.
134 */
135 private ReentrantLock groupCheckerLock;
Andreas Pantelopoulos89369462018-05-30 14:30:24 -0700136
Charles Chan053b1cb2017-03-22 16:56:35 -0700137 @Override
138 protected boolean requireVlanExtensions() {
139 return false;
140 }
141
Charles Chan425854b2016-04-11 15:32:12 -0700142 @Override
Harshada Chaundkar77958a52019-08-05 15:33:30 +0000143 protected boolean requireEthType() {
144 return false;
145 }
146
147 @Override
pierventreb58e9c92020-05-22 09:42:31 -0700148 public boolean requireSecondVlanTableEntry() {
149 return false;
150 }
151
152 @Override
Charles Chan40132b32017-01-22 00:19:37 -0800153 protected void initDriverId() {
Charles Chan425854b2016-04-11 15:32:12 -0700154 driverId = coreService.registerApplication(
Charles Chanab591602019-01-22 17:25:04 -0800155 "org.onosproject.driver.OvsOfdpaPipeline");
Charles Chan40132b32017-01-22 00:19:37 -0800156 }
Charles Chan425854b2016-04-11 15:32:12 -0700157
Charles Chan40132b32017-01-22 00:19:37 -0800158 @Override
159 protected void initGroupHander(PipelinerContext context) {
pier9ada4192020-03-20 11:00:38 +0100160 // Terminate internal references
161 // We are terminating the references here
162 // because when the device is offline the apps
163 // are still sending flowobjectives
164 if (groupHandler != null) {
165 groupHandler.terminate();
166 }
Charles Chanab591602019-01-22 17:25:04 -0800167 groupHandler = new OvsOfdpaGroupHandler();
Charles Chan40132b32017-01-22 00:19:37 -0800168 groupHandler.init(deviceId, context);
Charles Chan425854b2016-04-11 15:32:12 -0700169 }
170
Andreas Pantelopoulos89369462018-05-30 14:30:24 -0700171 @Override
172 public void init(DeviceId deviceId, PipelinerContext context) {
pier561c8812020-05-20 22:50:30 +0200173 // Terminate internal references
174 // We are terminating the references here
175 // because when the device is offline the apps
176 // are still sending flowobjectives
177 if (groupChecker != null) {
178 groupChecker.shutdown();
pier6341ff82020-02-28 09:24:11 +0100179 }
pier561c8812020-05-20 22:50:30 +0200180 // create a new executor at each init and a new empty queue
181 groupChecker = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/driver",
182 "ovs-ofdpa-%d", log));
183 if (flowRuleQueue != null) {
184 flowRuleQueue.clear();
185 }
186 flowRuleQueue = new ConcurrentLinkedQueue<>();
187 groupCheckerLock = new ReentrantLock();
188 groupChecker.scheduleAtFixedRate(new PopVlanPuntGroupChecker(), 20, 50, TimeUnit.MILLISECONDS);
189 super.init(deviceId, context);
Andreas Pantelopoulos89369462018-05-30 14:30:24 -0700190 }
pier9469f3e2019-04-17 17:05:08 +0200191
Andrea Campanella7c977b92018-05-30 21:39:45 -0700192 protected void processFilter(FilteringObjective filteringObjective,
193 boolean install,
194 ApplicationId applicationId) {
pier9469f3e2019-04-17 17:05:08 +0200195 if (OfdpaPipelineUtility.isDoubleTagged(filteringObjective)) {
Andrea Campanella7c977b92018-05-30 21:39:45 -0700196 processDoubleTaggedFilter(filteringObjective, install, applicationId);
197 } else {
198 // If it is not a double-tagged filter, we fall back
199 // to the OFDPA 2.0 pipeline.
200 super.processFilter(filteringObjective, install, applicationId);
201 }
202 }
203
204 /**
Andrea Campanella7c977b92018-05-30 21:39:45 -0700205 * Determines if the forwarding objective will be used for double-tagged packets.
206 *
207 * @param fwd Forwarding objective
208 * @return True if the objective was created for double-tagged packets, false otherwise.
209 */
210 private boolean isDoubleTagged(ForwardingObjective fwd) {
211 if (fwd.nextId() != null) {
212 NextGroup next = getGroupForNextObjective(fwd.nextId());
213 if (next != null) {
214 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
215 // we only need the top level group's key
216 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
217 if (group != null) {
218 int groupId = group.id().id();
219 if (((groupId & ~TYPE_MASK) == L3_UNICAST_TYPE) &&
220 ((groupId & TYPE_L3UG_DOUBLE_VLAN_MASK) == TYPE_L3UG_DOUBLE_VLAN_MASK)) {
221 return true;
222 }
223 }
224 }
225 }
226 return false;
227 }
228
229 /**
230 * Configure filtering rules of outer and inner VLAN IDs, and a MAC address.
231 * Filtering happens in three tables (VLAN_TABLE, VLAN_1_TABLE, TMAC_TABLE).
232 *
233 * @param filteringObjective the filtering objective
234 * @param install true to add, false to remove
235 * @param applicationId for application programming this filter
236 */
237 private void processDoubleTaggedFilter(FilteringObjective filteringObjective,
238 boolean install,
239 ApplicationId applicationId) {
240 PortCriterion portCriterion = null;
241 EthCriterion ethCriterion = null;
242 VlanIdCriterion innervidCriterion = null;
243 VlanIdCriterion outerVidCriterion = null;
244 boolean popVlan = false;
245 TrafficTreatment meta = filteringObjective.meta();
246 if (!filteringObjective.key().equals(Criteria.dummy()) &&
247 filteringObjective.key().type() == Criterion.Type.IN_PORT) {
248 portCriterion = (PortCriterion) filteringObjective.key();
249 }
250 if (portCriterion == null) {
251 log.warn("No IN_PORT defined in filtering objective from app: {}" +
252 "Failed to program VLAN tables.", applicationId);
253 return;
254 } else {
255 log.debug("Received filtering objective for dev/port: {}/{}", deviceId,
256 portCriterion.port());
257 }
258
259 // meta should have only one instruction, popVlan.
260 if (meta != null && meta.allInstructions().size() == 1) {
261 L2ModificationInstruction l2Inst = (L2ModificationInstruction) meta.allInstructions().get(0);
262 if (l2Inst.subtype().equals(L2ModificationInstruction.L2SubType.VLAN_POP)) {
263 popVlan = true;
264 } else {
265 log.warn("Filtering objective can have only VLAN_POP instruction.");
266 return;
267 }
268 } else {
269 log.warn("Filtering objective should have one instruction.");
270 return;
271 }
272
273 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
274 for (Criterion criterion : filteringObjective.conditions()) {
275 switch (criterion.type()) {
276 case ETH_DST:
277 case ETH_DST_MASKED:
278 ethCriterion = (EthCriterion) criterion;
279 break;
280 case VLAN_VID:
Daniele Morofa382c22019-07-12 17:58:54 -0700281 outerVidCriterion = (VlanIdCriterion) criterion;
282 break;
283 case INNER_VLAN_VID:
284 innervidCriterion = (VlanIdCriterion) criterion;
Andrea Campanella7c977b92018-05-30 21:39:45 -0700285 break;
286 default:
287 log.warn("Unsupported filter {}", criterion);
288 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
289 return;
290 }
291 }
292
293 if (innervidCriterion == null || outerVidCriterion == null) {
294 log.warn("filtering objective should have two vidCriterion.");
295 return;
296 }
297
298 if (ethCriterion == null || ethCriterion.mac().equals(NONE)) {
299 // NOTE: it is possible that a filtering objective only has vidCriterion
300 log.warn("filtering objective missing dstMac, cannot program TMAC table");
301 return;
302 } else {
303 MacAddress unicastMac = readEthDstFromTreatment(filteringObjective.meta());
304 List<List<FlowRule>> allStages = processEthDstFilter(portCriterion, ethCriterion, innervidCriterion,
305 innervidCriterion.vlanId(), unicastMac,
306 applicationId);
307 for (List<FlowRule> flowRules : allStages) {
308 log.trace("Starting a new flow rule stage for TMAC table flow");
309 ops.newStage();
310
311 for (FlowRule flowRule : flowRules) {
312 log.trace("{} flow rules in TMAC table: {} for dev: {}",
313 (install) ? "adding" : "removing", flowRules, deviceId);
314 if (install) {
315 ops = ops.add(flowRule);
316 } else {
317 // NOTE: Only remove TMAC flow when there is no more enabled port within the
318 // same VLAN on this device if TMAC doesn't support matching on in_port.
319 if (matchInPortTmacTable()
320 || (filteringObjective.meta() != null
321 && filteringObjective.meta().clearedDeferred())) {
322 ops = ops.remove(flowRule);
323 } else {
324 log.debug("Abort TMAC flow removal on {}. Some other ports still share this TMAC flow");
325 }
326 }
327 }
328 }
329 }
330
331 List<FlowRule> rules;
332 rules = processDoubleVlanIdFilter(portCriterion, innervidCriterion,
333 outerVidCriterion, popVlan, applicationId);
334 for (FlowRule flowRule : rules) {
335 log.trace("{} flow rule in VLAN table: {} for dev: {}",
336 (install) ? "adding" : "removing", flowRule, deviceId);
337 ops = install ? ops.add(flowRule) : ops.remove(flowRule);
338 }
339
340 // apply filtering flow rules
341 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
342 @Override
343 public void onSuccess(FlowRuleOperations ops) {
344 log.debug("Applied {} filtering rules in device {}",
345 ops.stages().get(0).size(), deviceId);
346 pass(filteringObjective);
347 }
348
349 @Override
350 public void onError(FlowRuleOperations ops) {
351 log.info("Failed to apply all filtering rules in dev {}", deviceId);
352 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
353 }
354 }));
355
356 }
357 /**
358 * Internal implementation of processDoubleVlanIdFilter.
359 *
360 * @param portCriterion port on device for which this filter is programmed
361 * @param innerVidCriterion inner vlan
362 * @param outerVidCriterion outer vlan
363 * @param popVlan true if outer vlan header needs to be removed
364 * @param applicationId for application programming this filter
365 * @return flow rules for port-vlan filters
366 */
367 private List<FlowRule> processDoubleVlanIdFilter(PortCriterion portCriterion,
368 VlanIdCriterion innerVidCriterion,
369 VlanIdCriterion outerVidCriterion,
370 boolean popVlan,
371 ApplicationId applicationId) {
372 List<FlowRule> rules = new ArrayList<>();
373 TrafficSelector.Builder outerSelector = DefaultTrafficSelector.builder();
374 TrafficTreatment.Builder outerTreatment = DefaultTrafficTreatment.builder();
375 TrafficSelector.Builder innerSelector = DefaultTrafficSelector.builder();
376 TrafficTreatment.Builder innerTreatment = DefaultTrafficTreatment.builder();
377
378 VlanId outerVlanId = outerVidCriterion.vlanId();
379 VlanId innerVlanId = innerVidCriterion.vlanId();
380 PortNumber portNumber = portCriterion.port();
381 // Check arguments
382 if (PortNumber.ALL.equals(portNumber)
383 || outerVlanId.equals(VlanId.NONE)
384 || innerVlanId.equals(VlanId.NONE)) {
385 log.warn("Incomplete Filtering Objective. " +
386 "VLAN Table cannot be programmed for {}", deviceId);
387 return ImmutableList.of();
388 } else {
389 outerSelector.matchInPort(portNumber);
390 innerSelector.matchInPort(portNumber);
391 outerTreatment.transition(VLAN_1_TABLE);
392 innerTreatment.transition(TMAC_TABLE);
393 outerTreatment.writeMetadata(outerVlanId.toShort(), 0xFFF);
394
395 outerSelector.matchVlanId(outerVlanId);
396 innerSelector.matchVlanId(innerVlanId);
397 //force recompilation
398 //FIXME might be issue due tu /fff mask
399 innerSelector.matchMetadata(outerVlanId.toShort());
400
401 if (popVlan) {
402 outerTreatment.popVlan();
403 }
404 }
405
406 // NOTE: for double-tagged packets, restore original outer vlan
407 // before sending it to the controller.
Charles Chanab591602019-01-22 17:25:04 -0800408 GroupKey groupKey = popVlanPuntGroupKey();
409 Group group = groupService.getGroup(deviceId, groupKey);
410 if (group != null) {
411 // push outer vlan and send to controller
412 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
413 .matchInPort(portNumber)
414 .matchVlanId(innerVlanId);
415 Host host = handler().get(HostService.class).getConnectedHosts(ConnectPoint.
416 deviceConnectPoint(deviceId + "/" + portNumber.toLong())).stream().filter(h ->
417 h.vlan().equals(outerVlanId)).findFirst().orElse(null);
418 EthType vlanType = EthType.EtherType.VLAN.ethType();
419 if (host != null) {
420 vlanType = host.tpid();
Andrea Campanella7c977b92018-05-30 21:39:45 -0700421 }
Charles Chanab591602019-01-22 17:25:04 -0800422 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
423 .pushVlan(vlanType).setVlanId(outerVlanId).punt();
424
425 rules.add(DefaultFlowRule.builder()
426 .forDevice(deviceId)
427 .withSelector(sbuilder.build())
428 .withTreatment(tbuilder.build())
429 .withPriority(PacketPriority.CONTROL.priorityValue())
430 .fromApp(driverId)
431 .makePermanent()
432 .forTable(PUNT_TABLE).build());
433 } else {
434 log.info("popVlanPuntGroup not found in dev:{}", deviceId);
435 return Collections.emptyList();
Andrea Campanella7c977b92018-05-30 21:39:45 -0700436 }
Charles Chanab591602019-01-22 17:25:04 -0800437
Andrea Campanella7c977b92018-05-30 21:39:45 -0700438 FlowRule outerRule = DefaultFlowRule.builder()
439 .forDevice(deviceId)
440 .withSelector(outerSelector.build())
441 .withTreatment(outerTreatment.build())
442 .withPriority(DEFAULT_PRIORITY)
443 .fromApp(applicationId)
444 .makePermanent()
445 .forTable(VLAN_TABLE)
446 .build();
447 FlowRule innerRule = DefaultFlowRule.builder()
448 .forDevice(deviceId)
449 .withSelector(innerSelector.build())
450 .withTreatment(innerTreatment.build())
451 .withPriority(DEFAULT_PRIORITY)
452 .fromApp(applicationId)
453 .makePermanent()
454 .forTable(VLAN_1_TABLE)
455 .build();
456 rules.add(outerRule);
457 rules.add(innerRule);
458
459 return rules;
460 }
461
462 /**
463 * In the OF-DPA 2.0 pipeline, egress forwarding objectives go to the
464 * egress tables.
465 * @param fwd the forwarding objective of type 'egress'
466 * @return a collection of flow rules to be sent to the switch. An empty
467 * collection may be returned if there is a problem in processing
468 * the flow rule
469 */
470 @Override
471 protected Collection<FlowRule> processEgress(ForwardingObjective fwd) {
472 log.debug("Processing egress forwarding objective:{} in dev:{}",
473 fwd, deviceId);
474
475 List<FlowRule> rules = new ArrayList<>();
476
477 // Build selector
478 TrafficSelector.Builder sb = DefaultTrafficSelector.builder();
479 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) fwd.selector().getCriterion(Criterion.Type.VLAN_VID);
480 if (vlanIdCriterion == null) {
481 log.error("Egress forwarding objective:{} must include vlanId", fwd.id());
482 fail(fwd, ObjectiveError.BADPARAMS);
483 return rules;
484 }
485
486 Optional<Instruction> outInstr = fwd.treatment().allInstructions().stream()
487 .filter(instruction -> instruction instanceof Instructions.OutputInstruction).findFirst();
488 if (!outInstr.isPresent()) {
489 log.error("Egress forwarding objective:{} must include output port", fwd.id());
490 fail(fwd, ObjectiveError.BADPARAMS);
491 return rules;
492 }
493
494 PortNumber portNumber = ((Instructions.OutputInstruction) outInstr.get()).port();
495
496 sb.matchVlanId(vlanIdCriterion.vlanId());
497 OfdpaMatchActsetOutput actsetOutput = new OfdpaMatchActsetOutput(portNumber);
498 sb.extension(actsetOutput, deviceId);
499
500 // Build a flow rule for Egress VLAN Flow table
501 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
502 tb.transition(UNICAST_ROUTING_TABLE_1);
503 if (fwd.treatment() != null) {
504 for (Instruction instr : fwd.treatment().allInstructions()) {
505 if (instr instanceof L2ModificationInstruction &&
506 ((L2ModificationInstruction) instr).subtype() ==
507 L2ModificationInstruction.L2SubType.VLAN_ID) {
508 tb.immediate().add(instr);
509 }
510 if (instr instanceof L2ModificationInstruction &&
511 ((L2ModificationInstruction) instr).subtype() ==
512 L2ModificationInstruction.L2SubType.VLAN_PUSH) {
513 EthType ethType = ((L2ModificationInstruction.ModVlanHeaderInstruction) instr).ethernetType();
514 tb.immediate().pushVlan(ethType);
515 }
516 }
517 }
518
519 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
520 .fromApp(fwd.appId())
521 .withPriority(fwd.priority())
522 .forDevice(deviceId)
523 .withSelector(sb.build())
524 .withTreatment(tb.build())
525 .makePermanent()
526 .forTable(EGRESS_VLAN_FLOW_TABLE_IN_INGRESS);
527 rules.add(ruleBuilder.build());
528 return rules;
529 }
530
531 /**
532 * Handles forwarding rules to the IP Unicast Routing.
533 *
534 * @param fwd the forwarding objective
535 * @return A collection of flow rules, or an empty set
536 */
537 protected Collection<FlowRule> processDoubleTaggedFwd(ForwardingObjective fwd) {
538 // inner for UNICAST_ROUTING_TABLE_1, outer for UNICAST_ROUTING_TABLE
539 TrafficSelector selector = fwd.selector();
540 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
541 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
542 TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
543
544 EthTypeCriterion ethType =
545 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
546
547 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
548 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
549 sBuilder.matchVlanId(VlanId.ANY);
550 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
551 if (!ipv4Dst.isMulticast() && ipv4Dst.prefixLength() == 32) {
552 sBuilder.matchIPDst(ipv4Dst);
553 if (fwd.nextId() != null) {
554 NextGroup next = getGroupForNextObjective(fwd.nextId());
555 if (next != null) {
556 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
557 // we only need the top level group's key to point the flow to it
558 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
559 if (group == null) {
560 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
561 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
562 fail(fwd, ObjectiveError.GROUPMISSING);
563 return Collections.emptySet();
564 }
565 outerTtb.immediate().setVlanId(extractDummyVlanIdFromGroupId(group.id().id()));
566 //ACTSET_OUTPUT in OVS will match output action in write_action() set.
567 outerTtb.deferred().setOutput(extractOutputPortFromGroupId(group.id().id()));
568 outerTtb.transition(EGRESS_VLAN_FLOW_TABLE_IN_INGRESS);
569 innerTtb.deferred().group(group.id());
570 innerTtb.transition(ACL_TABLE);
571
572 FlowRule.Builder innerRuleBuilder = DefaultFlowRule.builder()
573 .fromApp(fwd.appId())
574 .withPriority(fwd.priority())
575 .forDevice(deviceId)
576 .withSelector(sBuilder.build())
577 .withTreatment(innerTtb.build())
578 .forTable(UNICAST_ROUTING_TABLE_1);
579 if (fwd.permanent()) {
580 innerRuleBuilder.makePermanent();
581 } else {
582 innerRuleBuilder.makeTemporary(fwd.timeout());
583 }
584 Collection<FlowRule> flowRuleCollection = new HashSet<>();
585 flowRuleCollection.add(innerRuleBuilder.build());
586
587 FlowRule.Builder outerRuleBuilder = DefaultFlowRule.builder()
588 .fromApp(fwd.appId())
589 .withPriority(fwd.priority())
590 .forDevice(deviceId)
591 .withSelector(sBuilder.build())
592 .withTreatment(outerTtb.build())
593 .forTable(UNICAST_ROUTING_TABLE);
594 if (fwd.permanent()) {
595 outerRuleBuilder.makePermanent();
596 } else {
597 outerRuleBuilder.makeTemporary(fwd.timeout());
598 }
599 flowRuleCollection.add(innerRuleBuilder.build());
600 flowRuleCollection.add(outerRuleBuilder.build());
601 return flowRuleCollection;
602 } else {
603 log.warn("Cannot find group for nextId:{} in dev:{}. Aborting fwd:{}",
604 fwd.nextId(), deviceId, fwd.id());
605 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
606 return Collections.emptySet();
607 }
608 } else {
609 log.warn("NextId is not specified in fwd:{}", fwd.id());
610 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
611 return Collections.emptySet();
612 }
613 }
614 }
615 return Collections.emptySet();
616 }
617
618 private static VlanId extractDummyVlanIdFromGroupId(int groupId) {
619 short vlanId = (short) ((groupId & 0x7FF8000) >> 15);
620 return VlanId.vlanId(vlanId);
621 }
622
623 private static PortNumber extractOutputPortFromGroupId(int groupId) {
624 return PortNumber.portNumber(groupId & 0x7FFF);
625 }
626
Saurav Das4ce45962015-11-24 23:21:05 -0800627 /*
Charles Chanab591602019-01-22 17:25:04 -0800628 * Open vSwitch emulation does not require the non OF-standard rules for
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700629 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800630 *
631 * (non-Javadoc)
632 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
633 */
Saurav Das558afec2015-05-31 17:12:48 -0700634 @Override
Charles Chan66291502018-03-02 16:43:28 -0800635 protected List<List<FlowRule>> processVlanIdFilter(PortCriterion portCriterion,
pier6aef5b72019-06-10 17:10:26 +0200636 VlanIdCriterion vidCriterion,
637 VlanId assignedVlan,
638 ApplicationId applicationId,
639 boolean install) {
Charles Chan79769232016-07-05 16:34:39 -0700640 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800641 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
642 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
643 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800644 treatment.transition(TMAC_TABLE);
645
Saurav Das2857f382015-11-03 14:39:27 -0800646 if (vidCriterion.vlanId() == VlanId.NONE) {
647 // untagged packets are assigned vlans
648 treatment.pushVlan().setVlanId(assignedVlan);
Piere5bff482018-03-07 11:42:50 +0100649 } else if (!vidCriterion.vlanId().equals(assignedVlan)) {
650 // Rewrite with assigned vlans
651 treatment.setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800652 }
Saurav Das2857f382015-11-03 14:39:27 -0800653
654 // ofdpa cannot match on ALL portnumber, so we need to use separate
655 // rules for each port.
Charles Chan50d900c2018-03-02 13:26:22 -0800656 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeybe9f3bc2018-05-10 12:42:51 -0700657 if (portCriterion != null) {
658 if (portCriterion.port() == PortNumber.ALL) {
659 for (Port port : deviceService.getPorts(deviceId)) {
660 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
661 portnums.add(port.number());
662 }
Saurav Das2857f382015-11-03 14:39:27 -0800663 }
Ray Milkeybe9f3bc2018-05-10 12:42:51 -0700664 } else {
665 portnums.add(portCriterion.port());
Saurav Das2857f382015-11-03 14:39:27 -0800666 }
Saurav Das2857f382015-11-03 14:39:27 -0800667 }
Saurav Das4f980082015-11-05 13:39:15 -0800668
Saurav Das2857f382015-11-03 14:39:27 -0800669 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800670 // NOTE: Emulating OFDPA behavior by popping off internal assigned
671 // VLAN before sending to controller
Charles Chanab591602019-01-22 17:25:04 -0800672 if (vidCriterion.vlanId() == VlanId.NONE) {
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700673 try {
674 groupCheckerLock.lock();
675 if (flowRuleQueue == null) {
676 // this means that the group has been created
677 // and that groupChecker has destroyed the queue
678 log.debug("Installing punt table rule for untagged port {} and vlan {}.",
679 pnum, assignedVlan);
680 rules.add(buildPuntTableRule(pnum, assignedVlan));
681 } else {
682 // The VLAN punt group may be held back due to device initial audit.
683 // In that case, we queue all punt table flow until the group has been created.
684 log.debug("popVlanPuntGroup not found in dev:{}, queueing this flow rule.", deviceId);
685 flowRuleQueue.add(buildPuntTableRule(pnum, assignedVlan));
Andreas Pantelopoulos89369462018-05-30 14:30:24 -0700686 }
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700687 } finally {
688 groupCheckerLock.unlock();
Charles Chan0f43e472017-02-14 14:00:16 -0800689 }
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700690 } else if (vidCriterion.vlanId() != VlanId.NONE) {
691 // for tagged ports just forward to the controller
692 log.debug("Installing punt rule for tagged port {} and vlan {}.", pnum, vidCriterion.vlanId());
693 rules.add(buildPuntTableRuleTagged(pnum, vidCriterion.vlanId()));
Charles Chan0f43e472017-02-14 14:00:16 -0800694 }
695
Saurav Das4f980082015-11-05 13:39:15 -0800696 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800697 selector.matchInPort(pnum);
698 FlowRule rule = DefaultFlowRule.builder()
699 .forDevice(deviceId)
700 .withSelector(selector.build())
701 .withTreatment(treatment.build())
702 .withPriority(DEFAULT_PRIORITY)
703 .fromApp(applicationId)
704 .makePermanent()
705 .forTable(VLAN_TABLE).build();
706 rules.add(rule);
707 }
Charles Chanf57a8252016-06-29 19:12:37 -0700708
Charles Chan66291502018-03-02 16:43:28 -0800709 return ImmutableList.of(rules);
Saurav Das2857f382015-11-03 14:39:27 -0800710 }
711
Pier Ventree0ae7a32016-11-23 09:57:42 -0800712 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800713 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
714 * a group that pop vlan and punt.
715 *
716 * @param portNumber port number
717 * @param assignedVlan internally assigned vlan id
718 * @return punt table flow rule
719 */
720 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
721 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
722 .matchInPort(portNumber)
723 .matchVlanId(assignedVlan);
724 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
Yi Tsengfa394de2017-02-01 11:26:40 -0800725 .group(new GroupId(POP_VLAN_PUNT_GROUP_ID));
Charles Chan0f43e472017-02-14 14:00:16 -0800726
727 return DefaultFlowRule.builder()
728 .forDevice(deviceId)
729 .withSelector(sbuilder.build())
730 .withTreatment(tbuilder.build())
731 .withPriority(PacketPriority.CONTROL.priorityValue())
732 .fromApp(driverId)
733 .makePermanent()
734 .forTable(PUNT_TABLE).build();
735 }
736
737 /**
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700738 * Creates punt table entry that matches IN_PORT and VLAN_VID and forwards
739 * packet to controller tagged.
740 *
741 * @param portNumber port number
742 * @param packetVlan vlan tag of the packet
743 * @return punt table flow rule
744 */
745 private FlowRule buildPuntTableRuleTagged(PortNumber portNumber, VlanId packetVlan) {
746 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
747 .matchInPort(portNumber)
748 .matchVlanId(packetVlan);
749 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder().punt();
750
751 return DefaultFlowRule.builder()
752 .forDevice(deviceId)
753 .withSelector(sbuilder.build())
754 .withTreatment(tbuilder.build())
755 .withPriority(PacketPriority.CONTROL.priorityValue())
756 .fromApp(driverId)
757 .makePermanent()
758 .forTable(PUNT_TABLE).build();
759 }
760
Saurav Das8a0732e2015-11-20 15:27:53 -0800761 @Override
Charles Chan66291502018-03-02 16:43:28 -0800762 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das4ce45962015-11-24 23:21:05 -0800763 EthCriterion ethCriterion,
764 VlanIdCriterion vidCriterion,
765 VlanId assignedVlan,
Charles Chan45b69ab2018-03-02 15:41:41 -0800766 MacAddress unicastMac,
Saurav Das4ce45962015-11-24 23:21:05 -0800767 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800768 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
769 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
770 return processEthDstOnlyFilter(ethCriterion, applicationId);
771 }
772
Charles Chan5b9df8d2016-03-28 22:21:40 -0700773 // Multicast MAC
774 if (ethCriterion.mask() != null) {
Charles Chan45b69ab2018-03-02 15:41:41 -0800775 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700776 }
777
Saurav Das4ce45962015-11-24 23:21:05 -0800778 //handling untagged packets via assigned VLAN
779 if (vidCriterion.vlanId() == VlanId.NONE) {
780 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
781 }
782 // ofdpa cannot match on ALL portnumber, so we need to use separate
783 // rules for each port.
Charles Chan50d900c2018-03-02 13:26:22 -0800784 List<PortNumber> portnums = new ArrayList<>();
Ray Milkey74e59132018-01-17 15:24:52 -0800785 if (portCriterion != null) {
786 if (portCriterion.port() == PortNumber.ALL) {
787 for (Port port : deviceService.getPorts(deviceId)) {
788 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
789 portnums.add(port.number());
790 }
Saurav Das4ce45962015-11-24 23:21:05 -0800791 }
Ray Milkey74e59132018-01-17 15:24:52 -0800792 } else {
793 portnums.add(portCriterion.port());
Saurav Das4ce45962015-11-24 23:21:05 -0800794 }
Saurav Das4ce45962015-11-24 23:21:05 -0800795 }
796
Charles Chan50d900c2018-03-02 13:26:22 -0800797 List<FlowRule> rules = new ArrayList<>();
Saurav Das4ce45962015-11-24 23:21:05 -0800798 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800799 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800800 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
801 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
802 selector.matchInPort(pnum);
803 selector.matchVlanId(vidCriterion.vlanId());
804 selector.matchEthType(Ethernet.TYPE_IPV4);
805 selector.matchEthDst(ethCriterion.mac());
Saurav Das4ce45962015-11-24 23:21:05 -0800806 treatment.transition(UNICAST_ROUTING_TABLE);
807 FlowRule rule = DefaultFlowRule.builder()
808 .forDevice(deviceId)
809 .withSelector(selector.build())
810 .withTreatment(treatment.build())
811 .withPriority(DEFAULT_PRIORITY)
812 .fromApp(applicationId)
813 .makePermanent()
814 .forTable(TMAC_TABLE).build();
815 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800816
817 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800818 selector = DefaultTrafficSelector.builder();
819 treatment = DefaultTrafficTreatment.builder();
820 selector.matchInPort(pnum);
821 selector.matchVlanId(vidCriterion.vlanId());
822 selector.matchEthType(Ethernet.MPLS_UNICAST);
823 selector.matchEthDst(ethCriterion.mac());
Saurav Das4ce45962015-11-24 23:21:05 -0800824 treatment.transition(MPLS_TABLE_0);
825 rule = DefaultFlowRule.builder()
826 .forDevice(deviceId)
827 .withSelector(selector.build())
828 .withTreatment(treatment.build())
829 .withPriority(DEFAULT_PRIORITY)
830 .fromApp(applicationId)
831 .makePermanent()
832 .forTable(TMAC_TABLE).build();
833 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800834
835 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800836 selector = DefaultTrafficSelector.builder();
837 treatment = DefaultTrafficTreatment.builder();
838 selector.matchInPort(pnum);
839 selector.matchVlanId(vidCriterion.vlanId());
840 selector.matchEthType(Ethernet.TYPE_IPV6);
841 selector.matchEthDst(ethCriterion.mac());
Pier Ventree0ae7a32016-11-23 09:57:42 -0800842 treatment.transition(UNICAST_ROUTING_TABLE);
843 rule = DefaultFlowRule.builder()
844 .forDevice(deviceId)
845 .withSelector(selector.build())
846 .withTreatment(treatment.build())
847 .withPriority(DEFAULT_PRIORITY)
848 .fromApp(applicationId)
849 .makePermanent()
850 .forTable(TMAC_TABLE).build();
851 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800852 }
Charles Chan66291502018-03-02 16:43:28 -0800853 return ImmutableList.of(rules);
Saurav Das4ce45962015-11-24 23:21:05 -0800854 }
855
Charles Chan5270ed02016-01-30 23:22:37 -0800856 @Override
Charles Chan66291502018-03-02 16:43:28 -0800857 protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700858 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800859 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
860 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
861 selector.matchEthType(Ethernet.TYPE_IPV4);
862 selector.matchEthDst(ethCriterion.mac());
Charles Chan5270ed02016-01-30 23:22:37 -0800863 treatment.transition(UNICAST_ROUTING_TABLE);
864 FlowRule rule = DefaultFlowRule.builder()
865 .forDevice(deviceId)
866 .withSelector(selector.build())
867 .withTreatment(treatment.build())
868 .withPriority(DEFAULT_PRIORITY)
869 .fromApp(applicationId)
870 .makePermanent()
871 .forTable(TMAC_TABLE).build();
Charles Chan66291502018-03-02 16:43:28 -0800872 return ImmutableList.of(ImmutableList.of(rule));
Charles Chan5270ed02016-01-30 23:22:37 -0800873 }
874
Saurav Das4ce45962015-11-24 23:21:05 -0800875 /*
Charles Chanab591602019-01-22 17:25:04 -0800876 * Open vSwitch emulation allows MPLS ECMP.
Saurav Das4ce45962015-11-24 23:21:05 -0800877 *
878 * (non-Javadoc)
879 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
880 */
881 @Override
882 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Andrea Campanella7c977b92018-05-30 21:39:45 -0700883 if (isDoubleTagged(fwd)) {
884 return processDoubleTaggedFwd(fwd);
885 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800886 TrafficSelector selector = fwd.selector();
887 EthTypeCriterion ethType =
888 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
889 if ((ethType == null) ||
890 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800891 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
892 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800893 log.warn("processSpecific: Unsupported forwarding objective criteria"
894 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800895 fail(fwd, ObjectiveError.UNSUPPORTED);
896 return Collections.emptySet();
897 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800898 boolean defaultRule = false;
Charles Chan50d900c2018-03-02 13:26:22 -0800899 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800900 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800901 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
902
Saurav Das8a0732e2015-11-20 15:27:53 -0800903 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800904 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700905 if (ipv4Dst.isMulticast()) {
906 if (ipv4Dst.prefixLength() != 32) {
907 log.warn("Multicast specific forwarding objective can only be /32");
908 fail(fwd, ObjectiveError.BADPARAMS);
909 return ImmutableSet.of();
910 }
911 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
912 if (assignedVlan == null) {
913 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
914 fail(fwd, ObjectiveError.BADPARAMS);
915 return ImmutableSet.of();
916 }
917 filteredSelector.matchVlanId(assignedVlan);
918 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
919 forTableId = MULTICAST_ROUTING_TABLE;
920 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
921 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800922 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700923 if (ipv4Dst.prefixLength() == 0) {
924 // The entire IPV4_DST field is wildcarded intentionally
925 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700926 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700927 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700928 }
929 forTableId = UNICAST_ROUTING_TABLE;
930 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
931 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800932 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800933 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
Julia Ferguson65428c32017-08-10 18:15:24 +0000934 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
935 if (ipv6Dst.isMulticast()) {
936 if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
937 log.debug("Multicast specific IPv6 forwarding objective can only be /128");
938 fail(fwd, ObjectiveError.BADPARAMS);
939 return ImmutableSet.of();
940 }
941 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
942 if (assignedVlan == null) {
943 log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
944 fail(fwd, ObjectiveError.BADPARAMS);
945 return ImmutableSet.of();
946 }
947 filteredSelector.matchVlanId(assignedVlan);
948 filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
949 forTableId = MULTICAST_ROUTING_TABLE;
950 log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
951 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
952 } else {
953 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
954 return Collections.emptyList();
955 }
956 forTableId = UNICAST_ROUTING_TABLE;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800957 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800958 } else {
959 filteredSelector
960 .matchEthType(Ethernet.MPLS_UNICAST)
961 .matchMplsLabel(((MplsCriterion)
962 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
963 MplsBosCriterion bos = (MplsBosCriterion) selector
964 .getCriterion(Criterion.Type.MPLS_BOS);
965 if (bos != null) {
966 filteredSelector.matchMplsBos(bos.mplsBos());
967 }
968 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800969 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
970 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800971 }
972
973 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
974 if (fwd.treatment() != null) {
975 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chanab591602019-01-22 17:25:04 -0800976 if (i instanceof L3ModificationInstruction) {
Charles Chan40132b32017-01-22 00:19:37 -0800977 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
978 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
979 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
980 continue;
981 }
982 }
Charles Chan7d10b162015-12-07 18:54:45 -0800983 /*
984 * NOTE: OF-DPA does not support immediate instruction in
985 * L3 unicast and MPLS table.
986 */
987 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800988 }
989 }
990
991 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800992 NextGroup next = getGroupForNextObjective(fwd.nextId());
993 if (next != null) {
994 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
995 // we only need the top level group's key to point the flow to it
996 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
997 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700998 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
999 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -08001000 fail(fwd, ObjectiveError.GROUPMISSING);
1001 return Collections.emptySet();
1002 }
1003 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -08001004 }
Saurav Das8a0732e2015-11-20 15:27:53 -08001005 }
1006 tb.transition(ACL_TABLE);
1007 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
1008 .fromApp(fwd.appId())
1009 .withPriority(fwd.priority())
1010 .forDevice(deviceId)
1011 .withSelector(filteredSelector.build())
1012 .withTreatment(tb.build())
1013 .forTable(forTableId);
1014
1015 if (fwd.permanent()) {
1016 ruleBuilder.makePermanent();
1017 } else {
1018 ruleBuilder.makeTemporary(fwd.timeout());
1019 }
Flavio Castroe10fa242016-01-15 12:43:51 -08001020 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
1021 flowRuleCollection.add(ruleBuilder.build());
1022 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -08001023 flowRuleCollection.add(
1024 defaultRoute(fwd, complementarySelector, forTableId, tb)
1025 );
Flavio Castroe10fa242016-01-15 12:43:51 -08001026 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
1027 }
Flavio Castroe10fa242016-01-15 12:43:51 -08001028 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -08001029 }
1030
Charles Chan1e492d32016-01-30 23:22:37 -08001031 @Override
1032 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
1033 List<FlowRule> rules = new ArrayList<>();
1034
1035 // Build filtered selector
1036 TrafficSelector selector = fwd.selector();
1037 EthCriterion ethCriterion = (EthCriterion) selector
1038 .getCriterion(Criterion.Type.ETH_DST);
1039 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
Andrea Campanella7c977b92018-05-30 21:39:45 -07001040 .getCriterion(VLAN_VID);
Charles Chan1e492d32016-01-30 23:22:37 -08001041
1042 if (vlanIdCriterion == null) {
1043 log.warn("Forwarding objective for bridging requires vlan. Not "
1044 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
1045 fail(fwd, ObjectiveError.BADPARAMS);
1046 return Collections.emptySet();
1047 }
1048
1049 TrafficSelector.Builder filteredSelectorBuilder =
1050 DefaultTrafficSelector.builder();
1051 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -08001052 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -08001053 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
1054 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
1055 fwd.id(), fwd.nextId(), deviceId);
1056 } else {
1057 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
1058 + "in dev:{} for vlan:{}",
1059 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
1060 }
1061 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
1062 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
1063
1064 if (fwd.treatment() != null) {
1065 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
1066 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
1067 }
1068
1069 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1070 if (fwd.nextId() != null) {
1071 NextGroup next = getGroupForNextObjective(fwd.nextId());
1072 if (next != null) {
1073 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
1074 // we only need the top level group's key to point the flow to it
1075 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
1076 if (group != null) {
1077 treatmentBuilder.deferred().group(group.id());
1078 } else {
1079 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
1080 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
1081 fail(fwd, ObjectiveError.GROUPMISSING);
1082 return Collections.emptySet();
1083 }
1084 }
1085 }
1086 treatmentBuilder.immediate().transition(ACL_TABLE);
1087 TrafficTreatment filteredTreatment = treatmentBuilder.build();
1088
1089 // Build bridging table entries
1090 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
1091 flowRuleBuilder.fromApp(fwd.appId())
1092 .withPriority(fwd.priority())
1093 .forDevice(deviceId)
1094 .withSelector(filteredSelector)
1095 .withTreatment(filteredTreatment)
1096 .forTable(BRIDGING_TABLE);
1097 if (fwd.permanent()) {
1098 flowRuleBuilder.makePermanent();
1099 } else {
1100 flowRuleBuilder.makeTemporary(fwd.timeout());
1101 }
1102 rules.add(flowRuleBuilder.build());
1103 return rules;
1104 }
1105
Saurav Das52025962016-01-28 22:30:01 -08001106 @Override
Charles Chanab591602019-01-22 17:25:04 -08001107 protected TrafficTreatment.Builder versatileTreatmentBuilder(ForwardingObjective fwd) {
Saurav Das52025962016-01-28 22:30:01 -08001108 // XXX driver does not currently do type checking as per Tables 65-67 in
1109 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
1110 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
1111 if (fwd.treatment() != null) {
1112 for (Instruction ins : fwd.treatment().allInstructions()) {
1113 if (ins instanceof OutputInstruction) {
1114 OutputInstruction o = (OutputInstruction) ins;
Charles Chanab591602019-01-22 17:25:04 -08001115 if (PortNumber.CONTROLLER.equals(o.port())) {
Charles Chan0f43e472017-02-14 14:00:16 -08001116 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -08001117 } else {
1118 log.warn("Only allowed treatments in versatile forwarding "
1119 + "objectives are punts to the controller");
1120 }
Charles Chanf76de302018-06-15 18:54:18 -07001121 } else if (ins instanceof NoActionInstruction) {
1122 // No action is allowed and nothing needs to be done
Saurav Das52025962016-01-28 22:30:01 -08001123 } else {
1124 log.warn("Cannot process instruction in versatile fwd {}", ins);
1125 }
1126 }
Charles Chan2df0e8a2017-01-09 11:45:08 -08001127 if (fwd.treatment().clearedDeferred()) {
1128 ttBuilder.wipeDeferred();
1129 }
Saurav Das52025962016-01-28 22:30:01 -08001130 }
1131 if (fwd.nextId() != null) {
Charles Chanab591602019-01-22 17:25:04 -08001132 // Override case
Saurav Das52025962016-01-28 22:30:01 -08001133 NextGroup next = getGroupForNextObjective(fwd.nextId());
Charles Chanab591602019-01-22 17:25:04 -08001134 if (next == null) {
1135 fail(fwd, ObjectiveError.BADPARAMS);
1136 return null;
1137 }
Saurav Das52025962016-01-28 22:30:01 -08001138 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
1139 // we only need the top level group's key to point the flow to it
1140 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
1141 if (group == null) {
1142 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
Charles Chanab591602019-01-22 17:25:04 -08001143 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das52025962016-01-28 22:30:01 -08001144 fail(fwd, ObjectiveError.GROUPMISSING);
Charles Chanab591602019-01-22 17:25:04 -08001145 return null;
Saurav Das52025962016-01-28 22:30:01 -08001146 }
1147 ttBuilder.deferred().group(group.id());
1148 }
Charles Chanab591602019-01-22 17:25:04 -08001149 return ttBuilder;
Saurav Das52025962016-01-28 22:30:01 -08001150 }
1151
1152 /*
Charles Chanab591602019-01-22 17:25:04 -08001153 * Open vSwitch emulation requires table-miss-entries in forwarding tables.
Saurav Das52025962016-01-28 22:30:01 -08001154 * Real OFDPA does not require these rules as they are put in by default.
1155 *
1156 * (non-Javadoc)
1157 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
1158 */
Saurav Das2857f382015-11-03 14:39:27 -08001159 @Override
Saurav Das558afec2015-05-31 17:12:48 -07001160 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -08001161 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
1162 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
Andrea Campanella7c977b92018-05-30 21:39:45 -07001163 initTableMiss(VLAN_1_TABLE, ACL_TABLE, null);
Charles Chanf6ec1532017-02-08 16:10:40 -08001164 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
1165 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
1166 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
Andrea Campanella7c977b92018-05-30 21:39:45 -07001167 initTableMiss(EGRESS_VLAN_FLOW_TABLE_IN_INGRESS, ACL_TABLE, null);
1168 initTableMiss(UNICAST_ROUTING_TABLE_1, ACL_TABLE, null);
Charles Chanf6ec1532017-02-08 16:10:40 -08001169 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
1170 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
1171 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
1172 initTableMiss(ACL_TABLE, -1, null);
Charles Chan0ab4c272019-10-17 20:09:45 -07001173 initPuntTable();
Charles Chan0f43e472017-02-14 14:00:16 -08001174
Charles Chanab591602019-01-22 17:25:04 -08001175 initPopVlanPuntGroup();
Saurav Das558afec2015-05-31 17:12:48 -07001176 }
1177
Charles Chanf6ec1532017-02-08 16:10:40 -08001178 /**
1179 * Install table-miss flow entry.
1180 *
1181 * If treatment exists, use it directly.
1182 * Else if treatment does not exist but nextTable > 0, transit to next table.
1183 * Else apply empty treatment.
1184 *
1185 * @param thisTable this table ID
1186 * @param nextTable next table ID
1187 * @param treatment traffic treatment to apply.
1188 */
1189 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -07001190 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -08001191 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -07001192
Charles Chanf6ec1532017-02-08 16:10:40 -08001193 if (treatment == null) {
1194 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1195 if (nextTable > 0) {
1196 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -07001197 }
Charles Chanf6ec1532017-02-08 16:10:40 -08001198 treatment = tBuilder.build();
1199 }
Saurav Das558afec2015-05-31 17:12:48 -07001200
Charles Chanb7504392017-02-10 12:51:04 -08001201 FlowRule rule = DefaultFlowRule.builder()
1202 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -08001203 .withSelector(selector)
1204 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -08001205 .withPriority(LOWEST_PRIORITY)
1206 .fromApp(driverId)
1207 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -08001208 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -08001209 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -08001210
1211 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1212 @Override
1213 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -08001214 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -08001215 }
Saurav Das2857f382015-11-03 14:39:27 -08001216 @Override
1217 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -08001218 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -08001219 }
1220 }));
1221 }
Charles Chan0f43e472017-02-14 14:00:16 -08001222
1223 /**
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001224 * Install lldp/bbdp matching rules at table PUNT_TABLE
1225 * that forward traffic to controller.
1226 *
1227 */
Charles Chan0ab4c272019-10-17 20:09:45 -07001228 private void initPuntTable() {
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001229 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1230 TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build();
1231
Charles Chan0ab4c272019-10-17 20:09:45 -07001232 // Add punt rule for LLDP and BDDP
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001233 TrafficSelector.Builder lldpSelector = DefaultTrafficSelector.builder();
1234 lldpSelector.matchEthType(EthType.EtherType.LLDP.ethType().toShort());
1235 FlowRule lldpRule = DefaultFlowRule.builder()
1236 .forDevice(deviceId)
1237 .withSelector(lldpSelector.build())
1238 .withTreatment(treatment)
1239 .withPriority(HIGHEST_PRIORITY)
1240 .fromApp(driverId)
1241 .makePermanent()
1242 .forTable(PUNT_TABLE).build();
1243 ops = ops.add(lldpRule);
1244
1245 TrafficSelector.Builder bbdpSelector = DefaultTrafficSelector.builder();
1246 bbdpSelector.matchEthType(EthType.EtherType.BDDP.ethType().toShort());
1247 FlowRule bbdpRule = DefaultFlowRule.builder()
1248 .forDevice(deviceId)
1249 .withSelector(bbdpSelector.build())
1250 .withTreatment(treatment)
1251 .withPriority(HIGHEST_PRIORITY)
1252 .fromApp(driverId)
1253 .makePermanent()
1254 .forTable(PUNT_TABLE).build();
1255 ops.add(bbdpRule);
1256
1257 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1258 @Override
1259 public void onSuccess(FlowRuleOperations ops) {
Charles Chan0ab4c272019-10-17 20:09:45 -07001260 log.info("Initialized table {} on {}", PUNT_TABLE, deviceId);
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001261 }
1262 @Override
1263 public void onError(FlowRuleOperations ops) {
Charles Chan0ab4c272019-10-17 20:09:45 -07001264 log.warn("Failed to initialize table {} on {}", PUNT_TABLE, deviceId);
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001265 }
1266 }));
1267 }
1268
1269 /**
Charles Chan0f43e472017-02-14 14:00:16 -08001270 * Builds a indirect group contains pop_vlan and punt actions.
1271 * <p>
1272 * Using group instead of immediate action to ensure that
1273 * the copy of packet on the data plane is not affected by the pop vlan action.
1274 */
1275 private void initPopVlanPuntGroup() {
Yi Tsengef19de12017-04-24 11:33:05 -07001276 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -08001277 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
1278 .popVlan().punt().build();
1279 GroupBucket bucket =
1280 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
1281 GroupDescription groupDesc =
1282 new DefaultGroupDescription(
1283 deviceId,
1284 GroupDescription.Type.INDIRECT,
1285 new GroupBuckets(Collections.singletonList(bucket)),
1286 groupKey,
1287 POP_VLAN_PUNT_GROUP_ID,
1288 driverId);
1289 groupService.addGroup(groupDesc);
1290
1291 log.info("Initialized pop vlan punt group on {}", deviceId);
1292 }
Yi Tsengef19de12017-04-24 11:33:05 -07001293
1294 /**
1295 * Generates group key for a static indirect group that pop vlan and punt to
1296 * controller.
1297 *
1298 * @return the group key of the indirect table
1299 */
1300 private GroupKey popVlanPuntGroupKey() {
Charles Chan367c1c12018-10-19 16:23:28 -07001301 int hash = POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_NIBBLE_MASK);
Yi Tsengef19de12017-04-24 11:33:05 -07001302 return new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(hash));
1303 }
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001304
1305 private class PopVlanPuntGroupChecker implements Runnable {
1306 @Override
1307 public void run() {
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001308 try {
1309 groupCheckerLock.lock();
1310 // this can happen outside of the lock but I think it is safer
1311 // to include it here.
1312 Group group = groupService.getGroup(deviceId, popVlanPuntGroupKey());
Charles Chan4a288d92019-02-16 00:11:18 +00001313 if (group != null) {
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001314 log.debug("PopVlanPuntGroupChecker: Installing {} missing rules at punt table.",
1315 flowRuleQueue.size());
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001316
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001317 // if we have pending flow rules install them
1318 if (flowRuleQueue.size() > 0) {
1319 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1320 // we should not care about the context here, it can only be add
1321 // since when removing the rules the group should be there already.
1322 flowRuleQueue.forEach(ops::add);
1323 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1324 @Override
1325 public void onSuccess(FlowRuleOperations ops) {
1326 log.debug("Applied {} pop vlan punt rules in device {}",
1327 ops.stages().get(0).size(), deviceId);
1328 }
1329
1330 @Override
1331 public void onError(FlowRuleOperations ops) {
1332 log.error("Failed to apply all pop vlan punt rules in dev {}", deviceId);
1333 }
1334 }));
1335 }
1336 // this signifies that the group is created and now
1337 // flow rules can be installed directly
1338 flowRuleQueue = null;
pier0c9ace12020-01-23 11:59:56 +01001339 // Schedule with an initial delay the miss table flow rule installation
1340 // the delay is to make sure the queued flows are all installed before
1341 // pushing the table miss flow rule
1342 // TODO it can be further optimized by using context and completable future
1343 groupChecker.schedule(new TableMissFlowInstaller(), 5000, TimeUnit.MILLISECONDS);
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001344 }
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001345 } finally {
1346 groupCheckerLock.unlock();
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001347 }
1348 }
1349 }
pier0c9ace12020-01-23 11:59:56 +01001350
1351 private class TableMissFlowInstaller implements Runnable {
1352 @Override
1353 public void run() {
1354 // Add table miss flow rule
1355 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1356 TrafficSelector.Builder defaultSelector = DefaultTrafficSelector.builder();
1357 TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build();
1358 FlowRule defaultRule = DefaultFlowRule.builder()
1359 .forDevice(deviceId)
1360 .withSelector(defaultSelector.build())
1361 .withTreatment(treatment)
1362 .withPriority(LOWEST_PRIORITY)
1363 .fromApp(driverId)
1364 .makePermanent()
1365 .forTable(PUNT_TABLE).build();
1366 ops.add(defaultRule);
1367 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1368 @Override
1369 public void onSuccess(FlowRuleOperations ops) {
1370 log.info("Initialized table miss flow rule {} on {}", PUNT_TABLE, deviceId);
1371 }
1372 @Override
1373 public void onError(FlowRuleOperations ops) {
1374 log.warn("Failed to initialize table miss flow rule {} on {}", PUNT_TABLE, deviceId);
1375 }
1376 }));
1377 // shutdown the group checker gracefully
1378 groupChecker.shutdown();
1379 }
1380 }
Saurav Das558afec2015-05-31 17:12:48 -07001381}