blob: a9c15d88ca49979d73fa82030a1ea970d18c0e9b [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 */
112 private static final int PUNT_TABLE = 63;
113
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 */
Charles Chan07372342018-08-14 18:31:17 -0700120 private 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
Charles Chan40132b32017-01-22 00:19:37 -0800143 protected void initDriverId() {
Charles Chan425854b2016-04-11 15:32:12 -0700144 driverId = coreService.registerApplication(
Charles Chanab591602019-01-22 17:25:04 -0800145 "org.onosproject.driver.OvsOfdpaPipeline");
Charles Chan40132b32017-01-22 00:19:37 -0800146 }
Charles Chan425854b2016-04-11 15:32:12 -0700147
Charles Chan40132b32017-01-22 00:19:37 -0800148 @Override
149 protected void initGroupHander(PipelinerContext context) {
Charles Chanab591602019-01-22 17:25:04 -0800150 groupHandler = new OvsOfdpaGroupHandler();
Charles Chan40132b32017-01-22 00:19:37 -0800151 groupHandler.init(deviceId, context);
Charles Chan425854b2016-04-11 15:32:12 -0700152 }
153
Andreas Pantelopoulos89369462018-05-30 14:30:24 -0700154 @Override
155 public void init(DeviceId deviceId, PipelinerContext context) {
Charles Chanab591602019-01-22 17:25:04 -0800156 // create a new executor at each init and a new empty queue
157 groupChecker = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/driver",
158 "ovs-ofdpa-%d", log));
159 flowRuleQueue = new ConcurrentLinkedQueue<>();
160 groupCheckerLock = new ReentrantLock();
161 groupChecker.scheduleAtFixedRate(new PopVlanPuntGroupChecker(), 20, 50, TimeUnit.MILLISECONDS);
162 super.init(deviceId, context);
Andreas Pantelopoulos89369462018-05-30 14:30:24 -0700163 }
pier9469f3e2019-04-17 17:05:08 +0200164
Andrea Campanella7c977b92018-05-30 21:39:45 -0700165 protected void processFilter(FilteringObjective filteringObjective,
166 boolean install,
167 ApplicationId applicationId) {
pier9469f3e2019-04-17 17:05:08 +0200168 if (OfdpaPipelineUtility.isDoubleTagged(filteringObjective)) {
Andrea Campanella7c977b92018-05-30 21:39:45 -0700169 processDoubleTaggedFilter(filteringObjective, install, applicationId);
170 } else {
171 // If it is not a double-tagged filter, we fall back
172 // to the OFDPA 2.0 pipeline.
173 super.processFilter(filteringObjective, install, applicationId);
174 }
175 }
176
177 /**
Andrea Campanella7c977b92018-05-30 21:39:45 -0700178 * Determines if the forwarding objective will be used for double-tagged packets.
179 *
180 * @param fwd Forwarding objective
181 * @return True if the objective was created for double-tagged packets, false otherwise.
182 */
183 private boolean isDoubleTagged(ForwardingObjective fwd) {
184 if (fwd.nextId() != null) {
185 NextGroup next = getGroupForNextObjective(fwd.nextId());
186 if (next != null) {
187 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
188 // we only need the top level group's key
189 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
190 if (group != null) {
191 int groupId = group.id().id();
192 if (((groupId & ~TYPE_MASK) == L3_UNICAST_TYPE) &&
193 ((groupId & TYPE_L3UG_DOUBLE_VLAN_MASK) == TYPE_L3UG_DOUBLE_VLAN_MASK)) {
194 return true;
195 }
196 }
197 }
198 }
199 return false;
200 }
201
202 /**
203 * Configure filtering rules of outer and inner VLAN IDs, and a MAC address.
204 * Filtering happens in three tables (VLAN_TABLE, VLAN_1_TABLE, TMAC_TABLE).
205 *
206 * @param filteringObjective the filtering objective
207 * @param install true to add, false to remove
208 * @param applicationId for application programming this filter
209 */
210 private void processDoubleTaggedFilter(FilteringObjective filteringObjective,
211 boolean install,
212 ApplicationId applicationId) {
213 PortCriterion portCriterion = null;
214 EthCriterion ethCriterion = null;
215 VlanIdCriterion innervidCriterion = null;
216 VlanIdCriterion outerVidCriterion = null;
217 boolean popVlan = false;
218 TrafficTreatment meta = filteringObjective.meta();
219 if (!filteringObjective.key().equals(Criteria.dummy()) &&
220 filteringObjective.key().type() == Criterion.Type.IN_PORT) {
221 portCriterion = (PortCriterion) filteringObjective.key();
222 }
223 if (portCriterion == null) {
224 log.warn("No IN_PORT defined in filtering objective from app: {}" +
225 "Failed to program VLAN tables.", applicationId);
226 return;
227 } else {
228 log.debug("Received filtering objective for dev/port: {}/{}", deviceId,
229 portCriterion.port());
230 }
231
232 // meta should have only one instruction, popVlan.
233 if (meta != null && meta.allInstructions().size() == 1) {
234 L2ModificationInstruction l2Inst = (L2ModificationInstruction) meta.allInstructions().get(0);
235 if (l2Inst.subtype().equals(L2ModificationInstruction.L2SubType.VLAN_POP)) {
236 popVlan = true;
237 } else {
238 log.warn("Filtering objective can have only VLAN_POP instruction.");
239 return;
240 }
241 } else {
242 log.warn("Filtering objective should have one instruction.");
243 return;
244 }
245
246 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
247 for (Criterion criterion : filteringObjective.conditions()) {
248 switch (criterion.type()) {
249 case ETH_DST:
250 case ETH_DST_MASKED:
251 ethCriterion = (EthCriterion) criterion;
252 break;
253 case VLAN_VID:
Daniele Morofa382c22019-07-12 17:58:54 -0700254 outerVidCriterion = (VlanIdCriterion) criterion;
255 break;
256 case INNER_VLAN_VID:
257 innervidCriterion = (VlanIdCriterion) criterion;
Andrea Campanella7c977b92018-05-30 21:39:45 -0700258 break;
259 default:
260 log.warn("Unsupported filter {}", criterion);
261 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
262 return;
263 }
264 }
265
266 if (innervidCriterion == null || outerVidCriterion == null) {
267 log.warn("filtering objective should have two vidCriterion.");
268 return;
269 }
270
271 if (ethCriterion == null || ethCriterion.mac().equals(NONE)) {
272 // NOTE: it is possible that a filtering objective only has vidCriterion
273 log.warn("filtering objective missing dstMac, cannot program TMAC table");
274 return;
275 } else {
276 MacAddress unicastMac = readEthDstFromTreatment(filteringObjective.meta());
277 List<List<FlowRule>> allStages = processEthDstFilter(portCriterion, ethCriterion, innervidCriterion,
278 innervidCriterion.vlanId(), unicastMac,
279 applicationId);
280 for (List<FlowRule> flowRules : allStages) {
281 log.trace("Starting a new flow rule stage for TMAC table flow");
282 ops.newStage();
283
284 for (FlowRule flowRule : flowRules) {
285 log.trace("{} flow rules in TMAC table: {} for dev: {}",
286 (install) ? "adding" : "removing", flowRules, deviceId);
287 if (install) {
288 ops = ops.add(flowRule);
289 } else {
290 // NOTE: Only remove TMAC flow when there is no more enabled port within the
291 // same VLAN on this device if TMAC doesn't support matching on in_port.
292 if (matchInPortTmacTable()
293 || (filteringObjective.meta() != null
294 && filteringObjective.meta().clearedDeferred())) {
295 ops = ops.remove(flowRule);
296 } else {
297 log.debug("Abort TMAC flow removal on {}. Some other ports still share this TMAC flow");
298 }
299 }
300 }
301 }
302 }
303
304 List<FlowRule> rules;
305 rules = processDoubleVlanIdFilter(portCriterion, innervidCriterion,
306 outerVidCriterion, popVlan, applicationId);
307 for (FlowRule flowRule : rules) {
308 log.trace("{} flow rule in VLAN table: {} for dev: {}",
309 (install) ? "adding" : "removing", flowRule, deviceId);
310 ops = install ? ops.add(flowRule) : ops.remove(flowRule);
311 }
312
313 // apply filtering flow rules
314 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
315 @Override
316 public void onSuccess(FlowRuleOperations ops) {
317 log.debug("Applied {} filtering rules in device {}",
318 ops.stages().get(0).size(), deviceId);
319 pass(filteringObjective);
320 }
321
322 @Override
323 public void onError(FlowRuleOperations ops) {
324 log.info("Failed to apply all filtering rules in dev {}", deviceId);
325 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
326 }
327 }));
328
329 }
330 /**
331 * Internal implementation of processDoubleVlanIdFilter.
332 *
333 * @param portCriterion port on device for which this filter is programmed
334 * @param innerVidCriterion inner vlan
335 * @param outerVidCriterion outer vlan
336 * @param popVlan true if outer vlan header needs to be removed
337 * @param applicationId for application programming this filter
338 * @return flow rules for port-vlan filters
339 */
340 private List<FlowRule> processDoubleVlanIdFilter(PortCriterion portCriterion,
341 VlanIdCriterion innerVidCriterion,
342 VlanIdCriterion outerVidCriterion,
343 boolean popVlan,
344 ApplicationId applicationId) {
345 List<FlowRule> rules = new ArrayList<>();
346 TrafficSelector.Builder outerSelector = DefaultTrafficSelector.builder();
347 TrafficTreatment.Builder outerTreatment = DefaultTrafficTreatment.builder();
348 TrafficSelector.Builder innerSelector = DefaultTrafficSelector.builder();
349 TrafficTreatment.Builder innerTreatment = DefaultTrafficTreatment.builder();
350
351 VlanId outerVlanId = outerVidCriterion.vlanId();
352 VlanId innerVlanId = innerVidCriterion.vlanId();
353 PortNumber portNumber = portCriterion.port();
354 // Check arguments
355 if (PortNumber.ALL.equals(portNumber)
356 || outerVlanId.equals(VlanId.NONE)
357 || innerVlanId.equals(VlanId.NONE)) {
358 log.warn("Incomplete Filtering Objective. " +
359 "VLAN Table cannot be programmed for {}", deviceId);
360 return ImmutableList.of();
361 } else {
362 outerSelector.matchInPort(portNumber);
363 innerSelector.matchInPort(portNumber);
364 outerTreatment.transition(VLAN_1_TABLE);
365 innerTreatment.transition(TMAC_TABLE);
366 outerTreatment.writeMetadata(outerVlanId.toShort(), 0xFFF);
367
368 outerSelector.matchVlanId(outerVlanId);
369 innerSelector.matchVlanId(innerVlanId);
370 //force recompilation
371 //FIXME might be issue due tu /fff mask
372 innerSelector.matchMetadata(outerVlanId.toShort());
373
374 if (popVlan) {
375 outerTreatment.popVlan();
376 }
377 }
378
379 // NOTE: for double-tagged packets, restore original outer vlan
380 // before sending it to the controller.
Charles Chanab591602019-01-22 17:25:04 -0800381 GroupKey groupKey = popVlanPuntGroupKey();
382 Group group = groupService.getGroup(deviceId, groupKey);
383 if (group != null) {
384 // push outer vlan and send to controller
385 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
386 .matchInPort(portNumber)
387 .matchVlanId(innerVlanId);
388 Host host = handler().get(HostService.class).getConnectedHosts(ConnectPoint.
389 deviceConnectPoint(deviceId + "/" + portNumber.toLong())).stream().filter(h ->
390 h.vlan().equals(outerVlanId)).findFirst().orElse(null);
391 EthType vlanType = EthType.EtherType.VLAN.ethType();
392 if (host != null) {
393 vlanType = host.tpid();
Andrea Campanella7c977b92018-05-30 21:39:45 -0700394 }
Charles Chanab591602019-01-22 17:25:04 -0800395 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
396 .pushVlan(vlanType).setVlanId(outerVlanId).punt();
397
398 rules.add(DefaultFlowRule.builder()
399 .forDevice(deviceId)
400 .withSelector(sbuilder.build())
401 .withTreatment(tbuilder.build())
402 .withPriority(PacketPriority.CONTROL.priorityValue())
403 .fromApp(driverId)
404 .makePermanent()
405 .forTable(PUNT_TABLE).build());
406 } else {
407 log.info("popVlanPuntGroup not found in dev:{}", deviceId);
408 return Collections.emptyList();
Andrea Campanella7c977b92018-05-30 21:39:45 -0700409 }
Charles Chanab591602019-01-22 17:25:04 -0800410
Andrea Campanella7c977b92018-05-30 21:39:45 -0700411 FlowRule outerRule = DefaultFlowRule.builder()
412 .forDevice(deviceId)
413 .withSelector(outerSelector.build())
414 .withTreatment(outerTreatment.build())
415 .withPriority(DEFAULT_PRIORITY)
416 .fromApp(applicationId)
417 .makePermanent()
418 .forTable(VLAN_TABLE)
419 .build();
420 FlowRule innerRule = DefaultFlowRule.builder()
421 .forDevice(deviceId)
422 .withSelector(innerSelector.build())
423 .withTreatment(innerTreatment.build())
424 .withPriority(DEFAULT_PRIORITY)
425 .fromApp(applicationId)
426 .makePermanent()
427 .forTable(VLAN_1_TABLE)
428 .build();
429 rules.add(outerRule);
430 rules.add(innerRule);
431
432 return rules;
433 }
434
435 /**
436 * In the OF-DPA 2.0 pipeline, egress forwarding objectives go to the
437 * egress tables.
438 * @param fwd the forwarding objective of type 'egress'
439 * @return a collection of flow rules to be sent to the switch. An empty
440 * collection may be returned if there is a problem in processing
441 * the flow rule
442 */
443 @Override
444 protected Collection<FlowRule> processEgress(ForwardingObjective fwd) {
445 log.debug("Processing egress forwarding objective:{} in dev:{}",
446 fwd, deviceId);
447
448 List<FlowRule> rules = new ArrayList<>();
449
450 // Build selector
451 TrafficSelector.Builder sb = DefaultTrafficSelector.builder();
452 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) fwd.selector().getCriterion(Criterion.Type.VLAN_VID);
453 if (vlanIdCriterion == null) {
454 log.error("Egress forwarding objective:{} must include vlanId", fwd.id());
455 fail(fwd, ObjectiveError.BADPARAMS);
456 return rules;
457 }
458
459 Optional<Instruction> outInstr = fwd.treatment().allInstructions().stream()
460 .filter(instruction -> instruction instanceof Instructions.OutputInstruction).findFirst();
461 if (!outInstr.isPresent()) {
462 log.error("Egress forwarding objective:{} must include output port", fwd.id());
463 fail(fwd, ObjectiveError.BADPARAMS);
464 return rules;
465 }
466
467 PortNumber portNumber = ((Instructions.OutputInstruction) outInstr.get()).port();
468
469 sb.matchVlanId(vlanIdCriterion.vlanId());
470 OfdpaMatchActsetOutput actsetOutput = new OfdpaMatchActsetOutput(portNumber);
471 sb.extension(actsetOutput, deviceId);
472
473 // Build a flow rule for Egress VLAN Flow table
474 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
475 tb.transition(UNICAST_ROUTING_TABLE_1);
476 if (fwd.treatment() != null) {
477 for (Instruction instr : fwd.treatment().allInstructions()) {
478 if (instr instanceof L2ModificationInstruction &&
479 ((L2ModificationInstruction) instr).subtype() ==
480 L2ModificationInstruction.L2SubType.VLAN_ID) {
481 tb.immediate().add(instr);
482 }
483 if (instr instanceof L2ModificationInstruction &&
484 ((L2ModificationInstruction) instr).subtype() ==
485 L2ModificationInstruction.L2SubType.VLAN_PUSH) {
486 EthType ethType = ((L2ModificationInstruction.ModVlanHeaderInstruction) instr).ethernetType();
487 tb.immediate().pushVlan(ethType);
488 }
489 }
490 }
491
492 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
493 .fromApp(fwd.appId())
494 .withPriority(fwd.priority())
495 .forDevice(deviceId)
496 .withSelector(sb.build())
497 .withTreatment(tb.build())
498 .makePermanent()
499 .forTable(EGRESS_VLAN_FLOW_TABLE_IN_INGRESS);
500 rules.add(ruleBuilder.build());
501 return rules;
502 }
503
504 /**
505 * Handles forwarding rules to the IP Unicast Routing.
506 *
507 * @param fwd the forwarding objective
508 * @return A collection of flow rules, or an empty set
509 */
510 protected Collection<FlowRule> processDoubleTaggedFwd(ForwardingObjective fwd) {
511 // inner for UNICAST_ROUTING_TABLE_1, outer for UNICAST_ROUTING_TABLE
512 TrafficSelector selector = fwd.selector();
513 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
514 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
515 TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
516
517 EthTypeCriterion ethType =
518 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
519
520 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
521 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
522 sBuilder.matchVlanId(VlanId.ANY);
523 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
524 if (!ipv4Dst.isMulticast() && ipv4Dst.prefixLength() == 32) {
525 sBuilder.matchIPDst(ipv4Dst);
526 if (fwd.nextId() != null) {
527 NextGroup next = getGroupForNextObjective(fwd.nextId());
528 if (next != null) {
529 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
530 // we only need the top level group's key to point the flow to it
531 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
532 if (group == null) {
533 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
534 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
535 fail(fwd, ObjectiveError.GROUPMISSING);
536 return Collections.emptySet();
537 }
538 outerTtb.immediate().setVlanId(extractDummyVlanIdFromGroupId(group.id().id()));
539 //ACTSET_OUTPUT in OVS will match output action in write_action() set.
540 outerTtb.deferred().setOutput(extractOutputPortFromGroupId(group.id().id()));
541 outerTtb.transition(EGRESS_VLAN_FLOW_TABLE_IN_INGRESS);
542 innerTtb.deferred().group(group.id());
543 innerTtb.transition(ACL_TABLE);
544
545 FlowRule.Builder innerRuleBuilder = DefaultFlowRule.builder()
546 .fromApp(fwd.appId())
547 .withPriority(fwd.priority())
548 .forDevice(deviceId)
549 .withSelector(sBuilder.build())
550 .withTreatment(innerTtb.build())
551 .forTable(UNICAST_ROUTING_TABLE_1);
552 if (fwd.permanent()) {
553 innerRuleBuilder.makePermanent();
554 } else {
555 innerRuleBuilder.makeTemporary(fwd.timeout());
556 }
557 Collection<FlowRule> flowRuleCollection = new HashSet<>();
558 flowRuleCollection.add(innerRuleBuilder.build());
559
560 FlowRule.Builder outerRuleBuilder = DefaultFlowRule.builder()
561 .fromApp(fwd.appId())
562 .withPriority(fwd.priority())
563 .forDevice(deviceId)
564 .withSelector(sBuilder.build())
565 .withTreatment(outerTtb.build())
566 .forTable(UNICAST_ROUTING_TABLE);
567 if (fwd.permanent()) {
568 outerRuleBuilder.makePermanent();
569 } else {
570 outerRuleBuilder.makeTemporary(fwd.timeout());
571 }
572 flowRuleCollection.add(innerRuleBuilder.build());
573 flowRuleCollection.add(outerRuleBuilder.build());
574 return flowRuleCollection;
575 } else {
576 log.warn("Cannot find group for nextId:{} in dev:{}. Aborting fwd:{}",
577 fwd.nextId(), deviceId, fwd.id());
578 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
579 return Collections.emptySet();
580 }
581 } else {
582 log.warn("NextId is not specified in fwd:{}", fwd.id());
583 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
584 return Collections.emptySet();
585 }
586 }
587 }
588 return Collections.emptySet();
589 }
590
591 private static VlanId extractDummyVlanIdFromGroupId(int groupId) {
592 short vlanId = (short) ((groupId & 0x7FF8000) >> 15);
593 return VlanId.vlanId(vlanId);
594 }
595
596 private static PortNumber extractOutputPortFromGroupId(int groupId) {
597 return PortNumber.portNumber(groupId & 0x7FFF);
598 }
599
Saurav Das4ce45962015-11-24 23:21:05 -0800600 /*
Charles Chanab591602019-01-22 17:25:04 -0800601 * Open vSwitch emulation does not require the non OF-standard rules for
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700602 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800603 *
604 * (non-Javadoc)
605 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
606 */
Saurav Das558afec2015-05-31 17:12:48 -0700607 @Override
Charles Chan66291502018-03-02 16:43:28 -0800608 protected List<List<FlowRule>> processVlanIdFilter(PortCriterion portCriterion,
pier6aef5b72019-06-10 17:10:26 +0200609 VlanIdCriterion vidCriterion,
610 VlanId assignedVlan,
611 ApplicationId applicationId,
612 boolean install) {
Charles Chan79769232016-07-05 16:34:39 -0700613 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800614 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
615 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
616 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800617 treatment.transition(TMAC_TABLE);
618
Saurav Das2857f382015-11-03 14:39:27 -0800619 if (vidCriterion.vlanId() == VlanId.NONE) {
620 // untagged packets are assigned vlans
621 treatment.pushVlan().setVlanId(assignedVlan);
Piere5bff482018-03-07 11:42:50 +0100622 } else if (!vidCriterion.vlanId().equals(assignedVlan)) {
623 // Rewrite with assigned vlans
624 treatment.setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800625 }
Saurav Das2857f382015-11-03 14:39:27 -0800626
627 // ofdpa cannot match on ALL portnumber, so we need to use separate
628 // rules for each port.
Charles Chan50d900c2018-03-02 13:26:22 -0800629 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeybe9f3bc2018-05-10 12:42:51 -0700630 if (portCriterion != null) {
631 if (portCriterion.port() == PortNumber.ALL) {
632 for (Port port : deviceService.getPorts(deviceId)) {
633 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
634 portnums.add(port.number());
635 }
Saurav Das2857f382015-11-03 14:39:27 -0800636 }
Ray Milkeybe9f3bc2018-05-10 12:42:51 -0700637 } else {
638 portnums.add(portCriterion.port());
Saurav Das2857f382015-11-03 14:39:27 -0800639 }
Saurav Das2857f382015-11-03 14:39:27 -0800640 }
Saurav Das4f980082015-11-05 13:39:15 -0800641
Saurav Das2857f382015-11-03 14:39:27 -0800642 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800643 // NOTE: Emulating OFDPA behavior by popping off internal assigned
644 // VLAN before sending to controller
Charles Chanab591602019-01-22 17:25:04 -0800645 if (vidCriterion.vlanId() == VlanId.NONE) {
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700646 try {
647 groupCheckerLock.lock();
648 if (flowRuleQueue == null) {
649 // this means that the group has been created
650 // and that groupChecker has destroyed the queue
651 log.debug("Installing punt table rule for untagged port {} and vlan {}.",
652 pnum, assignedVlan);
653 rules.add(buildPuntTableRule(pnum, assignedVlan));
654 } else {
655 // The VLAN punt group may be held back due to device initial audit.
656 // In that case, we queue all punt table flow until the group has been created.
657 log.debug("popVlanPuntGroup not found in dev:{}, queueing this flow rule.", deviceId);
658 flowRuleQueue.add(buildPuntTableRule(pnum, assignedVlan));
Andreas Pantelopoulos89369462018-05-30 14:30:24 -0700659 }
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700660 } finally {
661 groupCheckerLock.unlock();
Charles Chan0f43e472017-02-14 14:00:16 -0800662 }
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700663 } else if (vidCriterion.vlanId() != VlanId.NONE) {
664 // for tagged ports just forward to the controller
665 log.debug("Installing punt rule for tagged port {} and vlan {}.", pnum, vidCriterion.vlanId());
666 rules.add(buildPuntTableRuleTagged(pnum, vidCriterion.vlanId()));
Charles Chan0f43e472017-02-14 14:00:16 -0800667 }
668
Saurav Das4f980082015-11-05 13:39:15 -0800669 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800670 selector.matchInPort(pnum);
671 FlowRule rule = DefaultFlowRule.builder()
672 .forDevice(deviceId)
673 .withSelector(selector.build())
674 .withTreatment(treatment.build())
675 .withPriority(DEFAULT_PRIORITY)
676 .fromApp(applicationId)
677 .makePermanent()
678 .forTable(VLAN_TABLE).build();
679 rules.add(rule);
680 }
Charles Chanf57a8252016-06-29 19:12:37 -0700681
Charles Chan66291502018-03-02 16:43:28 -0800682 return ImmutableList.of(rules);
Saurav Das2857f382015-11-03 14:39:27 -0800683 }
684
Pier Ventree0ae7a32016-11-23 09:57:42 -0800685 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800686 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
687 * a group that pop vlan and punt.
688 *
689 * @param portNumber port number
690 * @param assignedVlan internally assigned vlan id
691 * @return punt table flow rule
692 */
693 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
694 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
695 .matchInPort(portNumber)
696 .matchVlanId(assignedVlan);
697 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
Yi Tsengfa394de2017-02-01 11:26:40 -0800698 .group(new GroupId(POP_VLAN_PUNT_GROUP_ID));
Charles Chan0f43e472017-02-14 14:00:16 -0800699
700 return DefaultFlowRule.builder()
701 .forDevice(deviceId)
702 .withSelector(sbuilder.build())
703 .withTreatment(tbuilder.build())
704 .withPriority(PacketPriority.CONTROL.priorityValue())
705 .fromApp(driverId)
706 .makePermanent()
707 .forTable(PUNT_TABLE).build();
708 }
709
710 /**
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700711 * Creates punt table entry that matches IN_PORT and VLAN_VID and forwards
712 * packet to controller tagged.
713 *
714 * @param portNumber port number
715 * @param packetVlan vlan tag of the packet
716 * @return punt table flow rule
717 */
718 private FlowRule buildPuntTableRuleTagged(PortNumber portNumber, VlanId packetVlan) {
719 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
720 .matchInPort(portNumber)
721 .matchVlanId(packetVlan);
722 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder().punt();
723
724 return DefaultFlowRule.builder()
725 .forDevice(deviceId)
726 .withSelector(sbuilder.build())
727 .withTreatment(tbuilder.build())
728 .withPriority(PacketPriority.CONTROL.priorityValue())
729 .fromApp(driverId)
730 .makePermanent()
731 .forTable(PUNT_TABLE).build();
732 }
733
Saurav Das8a0732e2015-11-20 15:27:53 -0800734 @Override
Charles Chan66291502018-03-02 16:43:28 -0800735 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das4ce45962015-11-24 23:21:05 -0800736 EthCriterion ethCriterion,
737 VlanIdCriterion vidCriterion,
738 VlanId assignedVlan,
Charles Chan45b69ab2018-03-02 15:41:41 -0800739 MacAddress unicastMac,
Saurav Das4ce45962015-11-24 23:21:05 -0800740 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800741 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
742 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
743 return processEthDstOnlyFilter(ethCriterion, applicationId);
744 }
745
Charles Chan5b9df8d2016-03-28 22:21:40 -0700746 // Multicast MAC
747 if (ethCriterion.mask() != null) {
Charles Chan45b69ab2018-03-02 15:41:41 -0800748 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700749 }
750
Saurav Das4ce45962015-11-24 23:21:05 -0800751 //handling untagged packets via assigned VLAN
752 if (vidCriterion.vlanId() == VlanId.NONE) {
753 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
754 }
755 // ofdpa cannot match on ALL portnumber, so we need to use separate
756 // rules for each port.
Charles Chan50d900c2018-03-02 13:26:22 -0800757 List<PortNumber> portnums = new ArrayList<>();
Ray Milkey74e59132018-01-17 15:24:52 -0800758 if (portCriterion != null) {
759 if (portCriterion.port() == PortNumber.ALL) {
760 for (Port port : deviceService.getPorts(deviceId)) {
761 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
762 portnums.add(port.number());
763 }
Saurav Das4ce45962015-11-24 23:21:05 -0800764 }
Ray Milkey74e59132018-01-17 15:24:52 -0800765 } else {
766 portnums.add(portCriterion.port());
Saurav Das4ce45962015-11-24 23:21:05 -0800767 }
Saurav Das4ce45962015-11-24 23:21:05 -0800768 }
769
Charles Chan50d900c2018-03-02 13:26:22 -0800770 List<FlowRule> rules = new ArrayList<>();
Saurav Das4ce45962015-11-24 23:21:05 -0800771 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800772 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800773 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
774 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
775 selector.matchInPort(pnum);
776 selector.matchVlanId(vidCriterion.vlanId());
777 selector.matchEthType(Ethernet.TYPE_IPV4);
778 selector.matchEthDst(ethCriterion.mac());
Saurav Das4ce45962015-11-24 23:21:05 -0800779 treatment.transition(UNICAST_ROUTING_TABLE);
780 FlowRule rule = DefaultFlowRule.builder()
781 .forDevice(deviceId)
782 .withSelector(selector.build())
783 .withTreatment(treatment.build())
784 .withPriority(DEFAULT_PRIORITY)
785 .fromApp(applicationId)
786 .makePermanent()
787 .forTable(TMAC_TABLE).build();
788 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800789
790 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800791 selector = DefaultTrafficSelector.builder();
792 treatment = DefaultTrafficTreatment.builder();
793 selector.matchInPort(pnum);
794 selector.matchVlanId(vidCriterion.vlanId());
795 selector.matchEthType(Ethernet.MPLS_UNICAST);
796 selector.matchEthDst(ethCriterion.mac());
Saurav Das4ce45962015-11-24 23:21:05 -0800797 treatment.transition(MPLS_TABLE_0);
798 rule = DefaultFlowRule.builder()
799 .forDevice(deviceId)
800 .withSelector(selector.build())
801 .withTreatment(treatment.build())
802 .withPriority(DEFAULT_PRIORITY)
803 .fromApp(applicationId)
804 .makePermanent()
805 .forTable(TMAC_TABLE).build();
806 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800807
808 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800809 selector = DefaultTrafficSelector.builder();
810 treatment = DefaultTrafficTreatment.builder();
811 selector.matchInPort(pnum);
812 selector.matchVlanId(vidCriterion.vlanId());
813 selector.matchEthType(Ethernet.TYPE_IPV6);
814 selector.matchEthDst(ethCriterion.mac());
Pier Ventree0ae7a32016-11-23 09:57:42 -0800815 treatment.transition(UNICAST_ROUTING_TABLE);
816 rule = DefaultFlowRule.builder()
817 .forDevice(deviceId)
818 .withSelector(selector.build())
819 .withTreatment(treatment.build())
820 .withPriority(DEFAULT_PRIORITY)
821 .fromApp(applicationId)
822 .makePermanent()
823 .forTable(TMAC_TABLE).build();
824 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800825 }
Charles Chan66291502018-03-02 16:43:28 -0800826 return ImmutableList.of(rules);
Saurav Das4ce45962015-11-24 23:21:05 -0800827 }
828
Charles Chan5270ed02016-01-30 23:22:37 -0800829 @Override
Charles Chan66291502018-03-02 16:43:28 -0800830 protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700831 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800832 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
833 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
834 selector.matchEthType(Ethernet.TYPE_IPV4);
835 selector.matchEthDst(ethCriterion.mac());
Charles Chan5270ed02016-01-30 23:22:37 -0800836 treatment.transition(UNICAST_ROUTING_TABLE);
837 FlowRule rule = DefaultFlowRule.builder()
838 .forDevice(deviceId)
839 .withSelector(selector.build())
840 .withTreatment(treatment.build())
841 .withPriority(DEFAULT_PRIORITY)
842 .fromApp(applicationId)
843 .makePermanent()
844 .forTable(TMAC_TABLE).build();
Charles Chan66291502018-03-02 16:43:28 -0800845 return ImmutableList.of(ImmutableList.of(rule));
Charles Chan5270ed02016-01-30 23:22:37 -0800846 }
847
Saurav Das4ce45962015-11-24 23:21:05 -0800848 /*
Charles Chanab591602019-01-22 17:25:04 -0800849 * Open vSwitch emulation allows MPLS ECMP.
Saurav Das4ce45962015-11-24 23:21:05 -0800850 *
851 * (non-Javadoc)
852 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
853 */
854 @Override
855 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Andrea Campanella7c977b92018-05-30 21:39:45 -0700856 if (isDoubleTagged(fwd)) {
857 return processDoubleTaggedFwd(fwd);
858 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800859 TrafficSelector selector = fwd.selector();
860 EthTypeCriterion ethType =
861 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
862 if ((ethType == null) ||
863 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800864 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
865 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800866 log.warn("processSpecific: Unsupported forwarding objective criteria"
867 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800868 fail(fwd, ObjectiveError.UNSUPPORTED);
869 return Collections.emptySet();
870 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800871 boolean defaultRule = false;
Charles Chan50d900c2018-03-02 13:26:22 -0800872 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800873 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800874 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
875
Saurav Das8a0732e2015-11-20 15:27:53 -0800876 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800877 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700878 if (ipv4Dst.isMulticast()) {
879 if (ipv4Dst.prefixLength() != 32) {
880 log.warn("Multicast specific forwarding objective can only be /32");
881 fail(fwd, ObjectiveError.BADPARAMS);
882 return ImmutableSet.of();
883 }
884 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
885 if (assignedVlan == null) {
886 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
887 fail(fwd, ObjectiveError.BADPARAMS);
888 return ImmutableSet.of();
889 }
890 filteredSelector.matchVlanId(assignedVlan);
891 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
892 forTableId = MULTICAST_ROUTING_TABLE;
893 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
894 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800895 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700896 if (ipv4Dst.prefixLength() == 0) {
897 // The entire IPV4_DST field is wildcarded intentionally
898 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700899 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700900 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700901 }
902 forTableId = UNICAST_ROUTING_TABLE;
903 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
904 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800905 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800906 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
Julia Ferguson65428c32017-08-10 18:15:24 +0000907 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
908 if (ipv6Dst.isMulticast()) {
909 if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
910 log.debug("Multicast specific IPv6 forwarding objective can only be /128");
911 fail(fwd, ObjectiveError.BADPARAMS);
912 return ImmutableSet.of();
913 }
914 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
915 if (assignedVlan == null) {
916 log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
917 fail(fwd, ObjectiveError.BADPARAMS);
918 return ImmutableSet.of();
919 }
920 filteredSelector.matchVlanId(assignedVlan);
921 filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
922 forTableId = MULTICAST_ROUTING_TABLE;
923 log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
924 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
925 } else {
926 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
927 return Collections.emptyList();
928 }
929 forTableId = UNICAST_ROUTING_TABLE;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800930 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800931 } else {
932 filteredSelector
933 .matchEthType(Ethernet.MPLS_UNICAST)
934 .matchMplsLabel(((MplsCriterion)
935 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
936 MplsBosCriterion bos = (MplsBosCriterion) selector
937 .getCriterion(Criterion.Type.MPLS_BOS);
938 if (bos != null) {
939 filteredSelector.matchMplsBos(bos.mplsBos());
940 }
941 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800942 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
943 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800944 }
945
946 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
947 if (fwd.treatment() != null) {
948 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chanab591602019-01-22 17:25:04 -0800949 if (i instanceof L3ModificationInstruction) {
Charles Chan40132b32017-01-22 00:19:37 -0800950 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
951 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
952 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
953 continue;
954 }
955 }
Charles Chan7d10b162015-12-07 18:54:45 -0800956 /*
957 * NOTE: OF-DPA does not support immediate instruction in
958 * L3 unicast and MPLS table.
959 */
960 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800961 }
962 }
963
964 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800965 NextGroup next = getGroupForNextObjective(fwd.nextId());
966 if (next != null) {
967 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
968 // we only need the top level group's key to point the flow to it
969 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
970 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700971 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
972 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800973 fail(fwd, ObjectiveError.GROUPMISSING);
974 return Collections.emptySet();
975 }
976 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800977 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800978 }
979 tb.transition(ACL_TABLE);
980 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
981 .fromApp(fwd.appId())
982 .withPriority(fwd.priority())
983 .forDevice(deviceId)
984 .withSelector(filteredSelector.build())
985 .withTreatment(tb.build())
986 .forTable(forTableId);
987
988 if (fwd.permanent()) {
989 ruleBuilder.makePermanent();
990 } else {
991 ruleBuilder.makeTemporary(fwd.timeout());
992 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800993 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
994 flowRuleCollection.add(ruleBuilder.build());
995 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800996 flowRuleCollection.add(
997 defaultRoute(fwd, complementarySelector, forTableId, tb)
998 );
Flavio Castroe10fa242016-01-15 12:43:51 -0800999 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
1000 }
Flavio Castroe10fa242016-01-15 12:43:51 -08001001 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -08001002 }
1003
Charles Chan1e492d32016-01-30 23:22:37 -08001004 @Override
1005 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
1006 List<FlowRule> rules = new ArrayList<>();
1007
1008 // Build filtered selector
1009 TrafficSelector selector = fwd.selector();
1010 EthCriterion ethCriterion = (EthCriterion) selector
1011 .getCriterion(Criterion.Type.ETH_DST);
1012 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
Andrea Campanella7c977b92018-05-30 21:39:45 -07001013 .getCriterion(VLAN_VID);
Charles Chan1e492d32016-01-30 23:22:37 -08001014
1015 if (vlanIdCriterion == null) {
1016 log.warn("Forwarding objective for bridging requires vlan. Not "
1017 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
1018 fail(fwd, ObjectiveError.BADPARAMS);
1019 return Collections.emptySet();
1020 }
1021
1022 TrafficSelector.Builder filteredSelectorBuilder =
1023 DefaultTrafficSelector.builder();
1024 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -08001025 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -08001026 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
1027 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
1028 fwd.id(), fwd.nextId(), deviceId);
1029 } else {
1030 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
1031 + "in dev:{} for vlan:{}",
1032 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
1033 }
1034 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
1035 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
1036
1037 if (fwd.treatment() != null) {
1038 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
1039 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
1040 }
1041
1042 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1043 if (fwd.nextId() != null) {
1044 NextGroup next = getGroupForNextObjective(fwd.nextId());
1045 if (next != null) {
1046 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
1047 // we only need the top level group's key to point the flow to it
1048 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
1049 if (group != null) {
1050 treatmentBuilder.deferred().group(group.id());
1051 } else {
1052 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
1053 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
1054 fail(fwd, ObjectiveError.GROUPMISSING);
1055 return Collections.emptySet();
1056 }
1057 }
1058 }
1059 treatmentBuilder.immediate().transition(ACL_TABLE);
1060 TrafficTreatment filteredTreatment = treatmentBuilder.build();
1061
1062 // Build bridging table entries
1063 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
1064 flowRuleBuilder.fromApp(fwd.appId())
1065 .withPriority(fwd.priority())
1066 .forDevice(deviceId)
1067 .withSelector(filteredSelector)
1068 .withTreatment(filteredTreatment)
1069 .forTable(BRIDGING_TABLE);
1070 if (fwd.permanent()) {
1071 flowRuleBuilder.makePermanent();
1072 } else {
1073 flowRuleBuilder.makeTemporary(fwd.timeout());
1074 }
1075 rules.add(flowRuleBuilder.build());
1076 return rules;
1077 }
1078
Saurav Das52025962016-01-28 22:30:01 -08001079 @Override
Charles Chanab591602019-01-22 17:25:04 -08001080 protected TrafficTreatment.Builder versatileTreatmentBuilder(ForwardingObjective fwd) {
Saurav Das52025962016-01-28 22:30:01 -08001081 // XXX driver does not currently do type checking as per Tables 65-67 in
1082 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
1083 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
1084 if (fwd.treatment() != null) {
1085 for (Instruction ins : fwd.treatment().allInstructions()) {
1086 if (ins instanceof OutputInstruction) {
1087 OutputInstruction o = (OutputInstruction) ins;
Charles Chanab591602019-01-22 17:25:04 -08001088 if (PortNumber.CONTROLLER.equals(o.port())) {
Charles Chan0f43e472017-02-14 14:00:16 -08001089 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -08001090 } else {
1091 log.warn("Only allowed treatments in versatile forwarding "
1092 + "objectives are punts to the controller");
1093 }
Charles Chanf76de302018-06-15 18:54:18 -07001094 } else if (ins instanceof NoActionInstruction) {
1095 // No action is allowed and nothing needs to be done
Saurav Das52025962016-01-28 22:30:01 -08001096 } else {
1097 log.warn("Cannot process instruction in versatile fwd {}", ins);
1098 }
1099 }
Charles Chan2df0e8a2017-01-09 11:45:08 -08001100 if (fwd.treatment().clearedDeferred()) {
1101 ttBuilder.wipeDeferred();
1102 }
Saurav Das52025962016-01-28 22:30:01 -08001103 }
1104 if (fwd.nextId() != null) {
Charles Chanab591602019-01-22 17:25:04 -08001105 // Override case
Saurav Das52025962016-01-28 22:30:01 -08001106 NextGroup next = getGroupForNextObjective(fwd.nextId());
Charles Chanab591602019-01-22 17:25:04 -08001107 if (next == null) {
1108 fail(fwd, ObjectiveError.BADPARAMS);
1109 return null;
1110 }
Saurav Das52025962016-01-28 22:30:01 -08001111 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
1112 // we only need the top level group's key to point the flow to it
1113 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
1114 if (group == null) {
1115 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
Charles Chanab591602019-01-22 17:25:04 -08001116 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das52025962016-01-28 22:30:01 -08001117 fail(fwd, ObjectiveError.GROUPMISSING);
Charles Chanab591602019-01-22 17:25:04 -08001118 return null;
Saurav Das52025962016-01-28 22:30:01 -08001119 }
1120 ttBuilder.deferred().group(group.id());
1121 }
Charles Chanab591602019-01-22 17:25:04 -08001122 return ttBuilder;
Saurav Das52025962016-01-28 22:30:01 -08001123 }
1124
1125 /*
Charles Chanab591602019-01-22 17:25:04 -08001126 * Open vSwitch emulation requires table-miss-entries in forwarding tables.
Saurav Das52025962016-01-28 22:30:01 -08001127 * Real OFDPA does not require these rules as they are put in by default.
1128 *
1129 * (non-Javadoc)
1130 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
1131 */
Saurav Das2857f382015-11-03 14:39:27 -08001132 @Override
Saurav Das558afec2015-05-31 17:12:48 -07001133 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -08001134 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
1135 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
Andrea Campanella7c977b92018-05-30 21:39:45 -07001136 initTableMiss(VLAN_1_TABLE, ACL_TABLE, null);
Charles Chanf6ec1532017-02-08 16:10:40 -08001137 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
1138 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
1139 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
Andrea Campanella7c977b92018-05-30 21:39:45 -07001140 initTableMiss(EGRESS_VLAN_FLOW_TABLE_IN_INGRESS, ACL_TABLE, null);
1141 initTableMiss(UNICAST_ROUTING_TABLE_1, ACL_TABLE, null);
Charles Chanf6ec1532017-02-08 16:10:40 -08001142 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
1143 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
1144 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
1145 initTableMiss(ACL_TABLE, -1, null);
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001146 linkDiscoveryPuntTableRules();
Charles Chan0f43e472017-02-14 14:00:16 -08001147
Charles Chanab591602019-01-22 17:25:04 -08001148 initPopVlanPuntGroup();
Saurav Das558afec2015-05-31 17:12:48 -07001149 }
1150
Charles Chanf6ec1532017-02-08 16:10:40 -08001151 /**
1152 * Install table-miss flow entry.
1153 *
1154 * If treatment exists, use it directly.
1155 * Else if treatment does not exist but nextTable > 0, transit to next table.
1156 * Else apply empty treatment.
1157 *
1158 * @param thisTable this table ID
1159 * @param nextTable next table ID
1160 * @param treatment traffic treatment to apply.
1161 */
1162 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -07001163 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -08001164 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -07001165
Charles Chanf6ec1532017-02-08 16:10:40 -08001166 if (treatment == null) {
1167 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1168 if (nextTable > 0) {
1169 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -07001170 }
Charles Chanf6ec1532017-02-08 16:10:40 -08001171 treatment = tBuilder.build();
1172 }
Saurav Das558afec2015-05-31 17:12:48 -07001173
Charles Chanb7504392017-02-10 12:51:04 -08001174 FlowRule rule = DefaultFlowRule.builder()
1175 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -08001176 .withSelector(selector)
1177 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -08001178 .withPriority(LOWEST_PRIORITY)
1179 .fromApp(driverId)
1180 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -08001181 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -08001182 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -08001183
1184 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1185 @Override
1186 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -08001187 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -08001188 }
Saurav Das2857f382015-11-03 14:39:27 -08001189 @Override
1190 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -08001191 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -08001192 }
1193 }));
1194 }
Charles Chan0f43e472017-02-14 14:00:16 -08001195
1196 /**
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001197 * Install lldp/bbdp matching rules at table PUNT_TABLE
1198 * that forward traffic to controller.
1199 *
1200 */
1201 private void linkDiscoveryPuntTableRules() {
1202 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1203 TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build();
1204
1205 TrafficSelector.Builder lldpSelector = DefaultTrafficSelector.builder();
1206 lldpSelector.matchEthType(EthType.EtherType.LLDP.ethType().toShort());
1207 FlowRule lldpRule = DefaultFlowRule.builder()
1208 .forDevice(deviceId)
1209 .withSelector(lldpSelector.build())
1210 .withTreatment(treatment)
1211 .withPriority(HIGHEST_PRIORITY)
1212 .fromApp(driverId)
1213 .makePermanent()
1214 .forTable(PUNT_TABLE).build();
1215 ops = ops.add(lldpRule);
1216
1217 TrafficSelector.Builder bbdpSelector = DefaultTrafficSelector.builder();
1218 bbdpSelector.matchEthType(EthType.EtherType.BDDP.ethType().toShort());
1219 FlowRule bbdpRule = DefaultFlowRule.builder()
1220 .forDevice(deviceId)
1221 .withSelector(bbdpSelector.build())
1222 .withTreatment(treatment)
1223 .withPriority(HIGHEST_PRIORITY)
1224 .fromApp(driverId)
1225 .makePermanent()
1226 .forTable(PUNT_TABLE).build();
1227 ops.add(bbdpRule);
1228
1229 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1230 @Override
1231 public void onSuccess(FlowRuleOperations ops) {
1232 log.info("Added lldp/bbdp rules for table {} on {}", PUNT_TABLE, deviceId);
1233 }
1234 @Override
1235 public void onError(FlowRuleOperations ops) {
1236 log.warn("Failed to initialize lldp/bbdp rules for table {} on {}", PUNT_TABLE, deviceId);
1237 }
1238 }));
1239 }
1240
1241 /**
Charles Chan0f43e472017-02-14 14:00:16 -08001242 * Builds a indirect group contains pop_vlan and punt actions.
1243 * <p>
1244 * Using group instead of immediate action to ensure that
1245 * the copy of packet on the data plane is not affected by the pop vlan action.
1246 */
1247 private void initPopVlanPuntGroup() {
Yi Tsengef19de12017-04-24 11:33:05 -07001248 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -08001249 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
1250 .popVlan().punt().build();
1251 GroupBucket bucket =
1252 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
1253 GroupDescription groupDesc =
1254 new DefaultGroupDescription(
1255 deviceId,
1256 GroupDescription.Type.INDIRECT,
1257 new GroupBuckets(Collections.singletonList(bucket)),
1258 groupKey,
1259 POP_VLAN_PUNT_GROUP_ID,
1260 driverId);
1261 groupService.addGroup(groupDesc);
1262
1263 log.info("Initialized pop vlan punt group on {}", deviceId);
1264 }
Yi Tsengef19de12017-04-24 11:33:05 -07001265
1266 /**
1267 * Generates group key for a static indirect group that pop vlan and punt to
1268 * controller.
1269 *
1270 * @return the group key of the indirect table
1271 */
1272 private GroupKey popVlanPuntGroupKey() {
Charles Chan367c1c12018-10-19 16:23:28 -07001273 int hash = POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_NIBBLE_MASK);
Yi Tsengef19de12017-04-24 11:33:05 -07001274 return new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(hash));
1275 }
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001276
1277 private class PopVlanPuntGroupChecker implements Runnable {
1278 @Override
1279 public void run() {
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001280 try {
1281 groupCheckerLock.lock();
1282 // this can happen outside of the lock but I think it is safer
1283 // to include it here.
1284 Group group = groupService.getGroup(deviceId, popVlanPuntGroupKey());
Charles Chan4a288d92019-02-16 00:11:18 +00001285 if (group != null) {
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001286 log.debug("PopVlanPuntGroupChecker: Installing {} missing rules at punt table.",
1287 flowRuleQueue.size());
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001288
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001289 // if we have pending flow rules install them
1290 if (flowRuleQueue.size() > 0) {
1291 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1292 // we should not care about the context here, it can only be add
1293 // since when removing the rules the group should be there already.
1294 flowRuleQueue.forEach(ops::add);
1295 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1296 @Override
1297 public void onSuccess(FlowRuleOperations ops) {
1298 log.debug("Applied {} pop vlan punt rules in device {}",
1299 ops.stages().get(0).size(), deviceId);
1300 }
1301
1302 @Override
1303 public void onError(FlowRuleOperations ops) {
1304 log.error("Failed to apply all pop vlan punt rules in dev {}", deviceId);
1305 }
1306 }));
1307 }
1308 // this signifies that the group is created and now
1309 // flow rules can be installed directly
1310 flowRuleQueue = null;
1311 // shutdown the group checker gracefully
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001312 groupChecker.shutdown();
1313 }
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001314 } finally {
1315 groupCheckerLock.unlock();
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001316 }
1317 }
1318 }
Saurav Das558afec2015-05-31 17:12:48 -07001319}