blob: e3b4b06a66f163b71edde037071177109c659199 [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.*;
Andrea Campanella7c977b92018-05-30 21:39:45 -070093import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
94import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
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 }
Andrea Campanella7c977b92018-05-30 21:39:45 -0700164 protected void processFilter(FilteringObjective filteringObjective,
165 boolean install,
166 ApplicationId applicationId) {
167 if (isDoubleTagged(filteringObjective)) {
168 processDoubleTaggedFilter(filteringObjective, install, applicationId);
169 } else {
170 // If it is not a double-tagged filter, we fall back
171 // to the OFDPA 2.0 pipeline.
172 super.processFilter(filteringObjective, install, applicationId);
173 }
174 }
175
176 /**
177 * Determines if the filtering objective will be used for double-tagged packets.
178 *
179 * @param fob Filtering objective
180 * @return True if the objective was created for double-tagged packets, false otherwise.
181 */
182 private boolean isDoubleTagged(FilteringObjective fob) {
183 return fob.meta() != null &&
184 fob.meta().allInstructions().stream().anyMatch(inst -> inst.type() == L2MODIFICATION
185 && ((L2ModificationInstruction) inst).subtype() ==
186 L2ModificationInstruction.L2SubType.VLAN_POP) &&
187 fob.conditions().stream().filter(criterion -> criterion.type() == VLAN_VID).count() == 2;
188 }
189
190 /**
191 * Determines if the forwarding objective will be used for double-tagged packets.
192 *
193 * @param fwd Forwarding objective
194 * @return True if the objective was created for double-tagged packets, false otherwise.
195 */
196 private boolean isDoubleTagged(ForwardingObjective fwd) {
197 if (fwd.nextId() != null) {
198 NextGroup next = getGroupForNextObjective(fwd.nextId());
199 if (next != null) {
200 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
201 // we only need the top level group's key
202 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
203 if (group != null) {
204 int groupId = group.id().id();
205 if (((groupId & ~TYPE_MASK) == L3_UNICAST_TYPE) &&
206 ((groupId & TYPE_L3UG_DOUBLE_VLAN_MASK) == TYPE_L3UG_DOUBLE_VLAN_MASK)) {
207 return true;
208 }
209 }
210 }
211 }
212 return false;
213 }
214
215 /**
216 * Configure filtering rules of outer and inner VLAN IDs, and a MAC address.
217 * Filtering happens in three tables (VLAN_TABLE, VLAN_1_TABLE, TMAC_TABLE).
218 *
219 * @param filteringObjective the filtering objective
220 * @param install true to add, false to remove
221 * @param applicationId for application programming this filter
222 */
223 private void processDoubleTaggedFilter(FilteringObjective filteringObjective,
224 boolean install,
225 ApplicationId applicationId) {
226 PortCriterion portCriterion = null;
227 EthCriterion ethCriterion = null;
228 VlanIdCriterion innervidCriterion = null;
229 VlanIdCriterion outerVidCriterion = null;
230 boolean popVlan = false;
231 TrafficTreatment meta = filteringObjective.meta();
232 if (!filteringObjective.key().equals(Criteria.dummy()) &&
233 filteringObjective.key().type() == Criterion.Type.IN_PORT) {
234 portCriterion = (PortCriterion) filteringObjective.key();
235 }
236 if (portCriterion == null) {
237 log.warn("No IN_PORT defined in filtering objective from app: {}" +
238 "Failed to program VLAN tables.", applicationId);
239 return;
240 } else {
241 log.debug("Received filtering objective for dev/port: {}/{}", deviceId,
242 portCriterion.port());
243 }
244
245 // meta should have only one instruction, popVlan.
246 if (meta != null && meta.allInstructions().size() == 1) {
247 L2ModificationInstruction l2Inst = (L2ModificationInstruction) meta.allInstructions().get(0);
248 if (l2Inst.subtype().equals(L2ModificationInstruction.L2SubType.VLAN_POP)) {
249 popVlan = true;
250 } else {
251 log.warn("Filtering objective can have only VLAN_POP instruction.");
252 return;
253 }
254 } else {
255 log.warn("Filtering objective should have one instruction.");
256 return;
257 }
258
259 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
260 for (Criterion criterion : filteringObjective.conditions()) {
261 switch (criterion.type()) {
262 case ETH_DST:
263 case ETH_DST_MASKED:
264 ethCriterion = (EthCriterion) criterion;
265 break;
266 case VLAN_VID:
267 if (innervidCriterion == null) {
268 innervidCriterion = (VlanIdCriterion) criterion;
269 } else {
270 outerVidCriterion = innervidCriterion;
271 innervidCriterion = (VlanIdCriterion) criterion;
272 }
273 break;
274 default:
275 log.warn("Unsupported filter {}", criterion);
276 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
277 return;
278 }
279 }
280
281 if (innervidCriterion == null || outerVidCriterion == null) {
282 log.warn("filtering objective should have two vidCriterion.");
283 return;
284 }
285
286 if (ethCriterion == null || ethCriterion.mac().equals(NONE)) {
287 // NOTE: it is possible that a filtering objective only has vidCriterion
288 log.warn("filtering objective missing dstMac, cannot program TMAC table");
289 return;
290 } else {
291 MacAddress unicastMac = readEthDstFromTreatment(filteringObjective.meta());
292 List<List<FlowRule>> allStages = processEthDstFilter(portCriterion, ethCriterion, innervidCriterion,
293 innervidCriterion.vlanId(), unicastMac,
294 applicationId);
295 for (List<FlowRule> flowRules : allStages) {
296 log.trace("Starting a new flow rule stage for TMAC table flow");
297 ops.newStage();
298
299 for (FlowRule flowRule : flowRules) {
300 log.trace("{} flow rules in TMAC table: {} for dev: {}",
301 (install) ? "adding" : "removing", flowRules, deviceId);
302 if (install) {
303 ops = ops.add(flowRule);
304 } else {
305 // NOTE: Only remove TMAC flow when there is no more enabled port within the
306 // same VLAN on this device if TMAC doesn't support matching on in_port.
307 if (matchInPortTmacTable()
308 || (filteringObjective.meta() != null
309 && filteringObjective.meta().clearedDeferred())) {
310 ops = ops.remove(flowRule);
311 } else {
312 log.debug("Abort TMAC flow removal on {}. Some other ports still share this TMAC flow");
313 }
314 }
315 }
316 }
317 }
318
319 List<FlowRule> rules;
320 rules = processDoubleVlanIdFilter(portCriterion, innervidCriterion,
321 outerVidCriterion, popVlan, applicationId);
322 for (FlowRule flowRule : rules) {
323 log.trace("{} flow rule in VLAN table: {} for dev: {}",
324 (install) ? "adding" : "removing", flowRule, deviceId);
325 ops = install ? ops.add(flowRule) : ops.remove(flowRule);
326 }
327
328 // apply filtering flow rules
329 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
330 @Override
331 public void onSuccess(FlowRuleOperations ops) {
332 log.debug("Applied {} filtering rules in device {}",
333 ops.stages().get(0).size(), deviceId);
334 pass(filteringObjective);
335 }
336
337 @Override
338 public void onError(FlowRuleOperations ops) {
339 log.info("Failed to apply all filtering rules in dev {}", deviceId);
340 fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
341 }
342 }));
343
344 }
345 /**
346 * Internal implementation of processDoubleVlanIdFilter.
347 *
348 * @param portCriterion port on device for which this filter is programmed
349 * @param innerVidCriterion inner vlan
350 * @param outerVidCriterion outer vlan
351 * @param popVlan true if outer vlan header needs to be removed
352 * @param applicationId for application programming this filter
353 * @return flow rules for port-vlan filters
354 */
355 private List<FlowRule> processDoubleVlanIdFilter(PortCriterion portCriterion,
356 VlanIdCriterion innerVidCriterion,
357 VlanIdCriterion outerVidCriterion,
358 boolean popVlan,
359 ApplicationId applicationId) {
360 List<FlowRule> rules = new ArrayList<>();
361 TrafficSelector.Builder outerSelector = DefaultTrafficSelector.builder();
362 TrafficTreatment.Builder outerTreatment = DefaultTrafficTreatment.builder();
363 TrafficSelector.Builder innerSelector = DefaultTrafficSelector.builder();
364 TrafficTreatment.Builder innerTreatment = DefaultTrafficTreatment.builder();
365
366 VlanId outerVlanId = outerVidCriterion.vlanId();
367 VlanId innerVlanId = innerVidCriterion.vlanId();
368 PortNumber portNumber = portCriterion.port();
369 // Check arguments
370 if (PortNumber.ALL.equals(portNumber)
371 || outerVlanId.equals(VlanId.NONE)
372 || innerVlanId.equals(VlanId.NONE)) {
373 log.warn("Incomplete Filtering Objective. " +
374 "VLAN Table cannot be programmed for {}", deviceId);
375 return ImmutableList.of();
376 } else {
377 outerSelector.matchInPort(portNumber);
378 innerSelector.matchInPort(portNumber);
379 outerTreatment.transition(VLAN_1_TABLE);
380 innerTreatment.transition(TMAC_TABLE);
381 outerTreatment.writeMetadata(outerVlanId.toShort(), 0xFFF);
382
383 outerSelector.matchVlanId(outerVlanId);
384 innerSelector.matchVlanId(innerVlanId);
385 //force recompilation
386 //FIXME might be issue due tu /fff mask
387 innerSelector.matchMetadata(outerVlanId.toShort());
388
389 if (popVlan) {
390 outerTreatment.popVlan();
391 }
392 }
393
394 // NOTE: for double-tagged packets, restore original outer vlan
395 // before sending it to the controller.
Charles Chanab591602019-01-22 17:25:04 -0800396 GroupKey groupKey = popVlanPuntGroupKey();
397 Group group = groupService.getGroup(deviceId, groupKey);
398 if (group != null) {
399 // push outer vlan and send to controller
400 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
401 .matchInPort(portNumber)
402 .matchVlanId(innerVlanId);
403 Host host = handler().get(HostService.class).getConnectedHosts(ConnectPoint.
404 deviceConnectPoint(deviceId + "/" + portNumber.toLong())).stream().filter(h ->
405 h.vlan().equals(outerVlanId)).findFirst().orElse(null);
406 EthType vlanType = EthType.EtherType.VLAN.ethType();
407 if (host != null) {
408 vlanType = host.tpid();
Andrea Campanella7c977b92018-05-30 21:39:45 -0700409 }
Charles Chanab591602019-01-22 17:25:04 -0800410 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
411 .pushVlan(vlanType).setVlanId(outerVlanId).punt();
412
413 rules.add(DefaultFlowRule.builder()
414 .forDevice(deviceId)
415 .withSelector(sbuilder.build())
416 .withTreatment(tbuilder.build())
417 .withPriority(PacketPriority.CONTROL.priorityValue())
418 .fromApp(driverId)
419 .makePermanent()
420 .forTable(PUNT_TABLE).build());
421 } else {
422 log.info("popVlanPuntGroup not found in dev:{}", deviceId);
423 return Collections.emptyList();
Andrea Campanella7c977b92018-05-30 21:39:45 -0700424 }
Charles Chanab591602019-01-22 17:25:04 -0800425
Andrea Campanella7c977b92018-05-30 21:39:45 -0700426 FlowRule outerRule = DefaultFlowRule.builder()
427 .forDevice(deviceId)
428 .withSelector(outerSelector.build())
429 .withTreatment(outerTreatment.build())
430 .withPriority(DEFAULT_PRIORITY)
431 .fromApp(applicationId)
432 .makePermanent()
433 .forTable(VLAN_TABLE)
434 .build();
435 FlowRule innerRule = DefaultFlowRule.builder()
436 .forDevice(deviceId)
437 .withSelector(innerSelector.build())
438 .withTreatment(innerTreatment.build())
439 .withPriority(DEFAULT_PRIORITY)
440 .fromApp(applicationId)
441 .makePermanent()
442 .forTable(VLAN_1_TABLE)
443 .build();
444 rules.add(outerRule);
445 rules.add(innerRule);
446
447 return rules;
448 }
449
450 /**
451 * In the OF-DPA 2.0 pipeline, egress forwarding objectives go to the
452 * egress tables.
453 * @param fwd the forwarding objective of type 'egress'
454 * @return a collection of flow rules to be sent to the switch. An empty
455 * collection may be returned if there is a problem in processing
456 * the flow rule
457 */
458 @Override
459 protected Collection<FlowRule> processEgress(ForwardingObjective fwd) {
460 log.debug("Processing egress forwarding objective:{} in dev:{}",
461 fwd, deviceId);
462
463 List<FlowRule> rules = new ArrayList<>();
464
465 // Build selector
466 TrafficSelector.Builder sb = DefaultTrafficSelector.builder();
467 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) fwd.selector().getCriterion(Criterion.Type.VLAN_VID);
468 if (vlanIdCriterion == null) {
469 log.error("Egress forwarding objective:{} must include vlanId", fwd.id());
470 fail(fwd, ObjectiveError.BADPARAMS);
471 return rules;
472 }
473
474 Optional<Instruction> outInstr = fwd.treatment().allInstructions().stream()
475 .filter(instruction -> instruction instanceof Instructions.OutputInstruction).findFirst();
476 if (!outInstr.isPresent()) {
477 log.error("Egress forwarding objective:{} must include output port", fwd.id());
478 fail(fwd, ObjectiveError.BADPARAMS);
479 return rules;
480 }
481
482 PortNumber portNumber = ((Instructions.OutputInstruction) outInstr.get()).port();
483
484 sb.matchVlanId(vlanIdCriterion.vlanId());
485 OfdpaMatchActsetOutput actsetOutput = new OfdpaMatchActsetOutput(portNumber);
486 sb.extension(actsetOutput, deviceId);
487
488 // Build a flow rule for Egress VLAN Flow table
489 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
490 tb.transition(UNICAST_ROUTING_TABLE_1);
491 if (fwd.treatment() != null) {
492 for (Instruction instr : fwd.treatment().allInstructions()) {
493 if (instr instanceof L2ModificationInstruction &&
494 ((L2ModificationInstruction) instr).subtype() ==
495 L2ModificationInstruction.L2SubType.VLAN_ID) {
496 tb.immediate().add(instr);
497 }
498 if (instr instanceof L2ModificationInstruction &&
499 ((L2ModificationInstruction) instr).subtype() ==
500 L2ModificationInstruction.L2SubType.VLAN_PUSH) {
501 EthType ethType = ((L2ModificationInstruction.ModVlanHeaderInstruction) instr).ethernetType();
502 tb.immediate().pushVlan(ethType);
503 }
504 }
505 }
506
507 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
508 .fromApp(fwd.appId())
509 .withPriority(fwd.priority())
510 .forDevice(deviceId)
511 .withSelector(sb.build())
512 .withTreatment(tb.build())
513 .makePermanent()
514 .forTable(EGRESS_VLAN_FLOW_TABLE_IN_INGRESS);
515 rules.add(ruleBuilder.build());
516 return rules;
517 }
518
519 /**
520 * Handles forwarding rules to the IP Unicast Routing.
521 *
522 * @param fwd the forwarding objective
523 * @return A collection of flow rules, or an empty set
524 */
525 protected Collection<FlowRule> processDoubleTaggedFwd(ForwardingObjective fwd) {
526 // inner for UNICAST_ROUTING_TABLE_1, outer for UNICAST_ROUTING_TABLE
527 TrafficSelector selector = fwd.selector();
528 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
529 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
530 TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
531
532 EthTypeCriterion ethType =
533 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
534
535 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
536 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
537 sBuilder.matchVlanId(VlanId.ANY);
538 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
539 if (!ipv4Dst.isMulticast() && ipv4Dst.prefixLength() == 32) {
540 sBuilder.matchIPDst(ipv4Dst);
541 if (fwd.nextId() != null) {
542 NextGroup next = getGroupForNextObjective(fwd.nextId());
543 if (next != null) {
544 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
545 // we only need the top level group's key to point the flow to it
546 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
547 if (group == null) {
548 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
549 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
550 fail(fwd, ObjectiveError.GROUPMISSING);
551 return Collections.emptySet();
552 }
553 outerTtb.immediate().setVlanId(extractDummyVlanIdFromGroupId(group.id().id()));
554 //ACTSET_OUTPUT in OVS will match output action in write_action() set.
555 outerTtb.deferred().setOutput(extractOutputPortFromGroupId(group.id().id()));
556 outerTtb.transition(EGRESS_VLAN_FLOW_TABLE_IN_INGRESS);
557 innerTtb.deferred().group(group.id());
558 innerTtb.transition(ACL_TABLE);
559
560 FlowRule.Builder innerRuleBuilder = DefaultFlowRule.builder()
561 .fromApp(fwd.appId())
562 .withPriority(fwd.priority())
563 .forDevice(deviceId)
564 .withSelector(sBuilder.build())
565 .withTreatment(innerTtb.build())
566 .forTable(UNICAST_ROUTING_TABLE_1);
567 if (fwd.permanent()) {
568 innerRuleBuilder.makePermanent();
569 } else {
570 innerRuleBuilder.makeTemporary(fwd.timeout());
571 }
572 Collection<FlowRule> flowRuleCollection = new HashSet<>();
573 flowRuleCollection.add(innerRuleBuilder.build());
574
575 FlowRule.Builder outerRuleBuilder = DefaultFlowRule.builder()
576 .fromApp(fwd.appId())
577 .withPriority(fwd.priority())
578 .forDevice(deviceId)
579 .withSelector(sBuilder.build())
580 .withTreatment(outerTtb.build())
581 .forTable(UNICAST_ROUTING_TABLE);
582 if (fwd.permanent()) {
583 outerRuleBuilder.makePermanent();
584 } else {
585 outerRuleBuilder.makeTemporary(fwd.timeout());
586 }
587 flowRuleCollection.add(innerRuleBuilder.build());
588 flowRuleCollection.add(outerRuleBuilder.build());
589 return flowRuleCollection;
590 } else {
591 log.warn("Cannot find group for nextId:{} in dev:{}. Aborting fwd:{}",
592 fwd.nextId(), deviceId, fwd.id());
593 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
594 return Collections.emptySet();
595 }
596 } else {
597 log.warn("NextId is not specified in fwd:{}", fwd.id());
598 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
599 return Collections.emptySet();
600 }
601 }
602 }
603 return Collections.emptySet();
604 }
605
606 private static VlanId extractDummyVlanIdFromGroupId(int groupId) {
607 short vlanId = (short) ((groupId & 0x7FF8000) >> 15);
608 return VlanId.vlanId(vlanId);
609 }
610
611 private static PortNumber extractOutputPortFromGroupId(int groupId) {
612 return PortNumber.portNumber(groupId & 0x7FFF);
613 }
614
Saurav Das4ce45962015-11-24 23:21:05 -0800615 /*
Charles Chanab591602019-01-22 17:25:04 -0800616 * Open vSwitch emulation does not require the non OF-standard rules for
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700617 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800618 *
619 * (non-Javadoc)
620 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
621 */
Saurav Das558afec2015-05-31 17:12:48 -0700622 @Override
Charles Chan66291502018-03-02 16:43:28 -0800623 protected List<List<FlowRule>> processVlanIdFilter(PortCriterion portCriterion,
Saurav Das2857f382015-11-03 14:39:27 -0800624 VlanIdCriterion vidCriterion,
625 VlanId assignedVlan,
626 ApplicationId applicationId) {
Charles Chan79769232016-07-05 16:34:39 -0700627 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800628 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
629 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
630 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800631 treatment.transition(TMAC_TABLE);
632
Saurav Das2857f382015-11-03 14:39:27 -0800633 if (vidCriterion.vlanId() == VlanId.NONE) {
634 // untagged packets are assigned vlans
635 treatment.pushVlan().setVlanId(assignedVlan);
Piere5bff482018-03-07 11:42:50 +0100636 } else if (!vidCriterion.vlanId().equals(assignedVlan)) {
637 // Rewrite with assigned vlans
638 treatment.setVlanId(assignedVlan);
Saurav Das2857f382015-11-03 14:39:27 -0800639 }
Saurav Das2857f382015-11-03 14:39:27 -0800640
641 // ofdpa cannot match on ALL portnumber, so we need to use separate
642 // rules for each port.
Charles Chan50d900c2018-03-02 13:26:22 -0800643 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeybe9f3bc2018-05-10 12:42:51 -0700644 if (portCriterion != null) {
645 if (portCriterion.port() == PortNumber.ALL) {
646 for (Port port : deviceService.getPorts(deviceId)) {
647 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
648 portnums.add(port.number());
649 }
Saurav Das2857f382015-11-03 14:39:27 -0800650 }
Ray Milkeybe9f3bc2018-05-10 12:42:51 -0700651 } else {
652 portnums.add(portCriterion.port());
Saurav Das2857f382015-11-03 14:39:27 -0800653 }
Saurav Das2857f382015-11-03 14:39:27 -0800654 }
Saurav Das4f980082015-11-05 13:39:15 -0800655
Saurav Das2857f382015-11-03 14:39:27 -0800656 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800657 // NOTE: Emulating OFDPA behavior by popping off internal assigned
658 // VLAN before sending to controller
Charles Chanab591602019-01-22 17:25:04 -0800659 if (vidCriterion.vlanId() == VlanId.NONE) {
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700660 try {
661 groupCheckerLock.lock();
662 if (flowRuleQueue == null) {
663 // this means that the group has been created
664 // and that groupChecker has destroyed the queue
665 log.debug("Installing punt table rule for untagged port {} and vlan {}.",
666 pnum, assignedVlan);
667 rules.add(buildPuntTableRule(pnum, assignedVlan));
668 } else {
669 // The VLAN punt group may be held back due to device initial audit.
670 // In that case, we queue all punt table flow until the group has been created.
671 log.debug("popVlanPuntGroup not found in dev:{}, queueing this flow rule.", deviceId);
672 flowRuleQueue.add(buildPuntTableRule(pnum, assignedVlan));
Andreas Pantelopoulos89369462018-05-30 14:30:24 -0700673 }
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700674 } finally {
675 groupCheckerLock.unlock();
Charles Chan0f43e472017-02-14 14:00:16 -0800676 }
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700677 } else if (vidCriterion.vlanId() != VlanId.NONE) {
678 // for tagged ports just forward to the controller
679 log.debug("Installing punt rule for tagged port {} and vlan {}.", pnum, vidCriterion.vlanId());
680 rules.add(buildPuntTableRuleTagged(pnum, vidCriterion.vlanId()));
Charles Chan0f43e472017-02-14 14:00:16 -0800681 }
682
Saurav Das4f980082015-11-05 13:39:15 -0800683 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800684 selector.matchInPort(pnum);
685 FlowRule rule = DefaultFlowRule.builder()
686 .forDevice(deviceId)
687 .withSelector(selector.build())
688 .withTreatment(treatment.build())
689 .withPriority(DEFAULT_PRIORITY)
690 .fromApp(applicationId)
691 .makePermanent()
692 .forTable(VLAN_TABLE).build();
693 rules.add(rule);
694 }
Charles Chanf57a8252016-06-29 19:12:37 -0700695
Charles Chan66291502018-03-02 16:43:28 -0800696 return ImmutableList.of(rules);
Saurav Das2857f382015-11-03 14:39:27 -0800697 }
698
Pier Ventree0ae7a32016-11-23 09:57:42 -0800699 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800700 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
701 * a group that pop vlan and punt.
702 *
703 * @param portNumber port number
704 * @param assignedVlan internally assigned vlan id
705 * @return punt table flow rule
706 */
707 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
708 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
709 .matchInPort(portNumber)
710 .matchVlanId(assignedVlan);
711 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
Yi Tsengfa394de2017-02-01 11:26:40 -0800712 .group(new GroupId(POP_VLAN_PUNT_GROUP_ID));
Charles Chan0f43e472017-02-14 14:00:16 -0800713
714 return DefaultFlowRule.builder()
715 .forDevice(deviceId)
716 .withSelector(sbuilder.build())
717 .withTreatment(tbuilder.build())
718 .withPriority(PacketPriority.CONTROL.priorityValue())
719 .fromApp(driverId)
720 .makePermanent()
721 .forTable(PUNT_TABLE).build();
722 }
723
724 /**
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -0700725 * Creates punt table entry that matches IN_PORT and VLAN_VID and forwards
726 * packet to controller tagged.
727 *
728 * @param portNumber port number
729 * @param packetVlan vlan tag of the packet
730 * @return punt table flow rule
731 */
732 private FlowRule buildPuntTableRuleTagged(PortNumber portNumber, VlanId packetVlan) {
733 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
734 .matchInPort(portNumber)
735 .matchVlanId(packetVlan);
736 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder().punt();
737
738 return DefaultFlowRule.builder()
739 .forDevice(deviceId)
740 .withSelector(sbuilder.build())
741 .withTreatment(tbuilder.build())
742 .withPriority(PacketPriority.CONTROL.priorityValue())
743 .fromApp(driverId)
744 .makePermanent()
745 .forTable(PUNT_TABLE).build();
746 }
747
Saurav Das8a0732e2015-11-20 15:27:53 -0800748 @Override
Charles Chan66291502018-03-02 16:43:28 -0800749 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das4ce45962015-11-24 23:21:05 -0800750 EthCriterion ethCriterion,
751 VlanIdCriterion vidCriterion,
752 VlanId assignedVlan,
Charles Chan45b69ab2018-03-02 15:41:41 -0800753 MacAddress unicastMac,
Saurav Das4ce45962015-11-24 23:21:05 -0800754 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800755 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
756 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
757 return processEthDstOnlyFilter(ethCriterion, applicationId);
758 }
759
Charles Chan5b9df8d2016-03-28 22:21:40 -0700760 // Multicast MAC
761 if (ethCriterion.mask() != null) {
Charles Chan45b69ab2018-03-02 15:41:41 -0800762 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700763 }
764
Saurav Das4ce45962015-11-24 23:21:05 -0800765 //handling untagged packets via assigned VLAN
766 if (vidCriterion.vlanId() == VlanId.NONE) {
767 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
768 }
769 // ofdpa cannot match on ALL portnumber, so we need to use separate
770 // rules for each port.
Charles Chan50d900c2018-03-02 13:26:22 -0800771 List<PortNumber> portnums = new ArrayList<>();
Ray Milkey74e59132018-01-17 15:24:52 -0800772 if (portCriterion != null) {
773 if (portCriterion.port() == PortNumber.ALL) {
774 for (Port port : deviceService.getPorts(deviceId)) {
775 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
776 portnums.add(port.number());
777 }
Saurav Das4ce45962015-11-24 23:21:05 -0800778 }
Ray Milkey74e59132018-01-17 15:24:52 -0800779 } else {
780 portnums.add(portCriterion.port());
Saurav Das4ce45962015-11-24 23:21:05 -0800781 }
Saurav Das4ce45962015-11-24 23:21:05 -0800782 }
783
Charles Chan50d900c2018-03-02 13:26:22 -0800784 List<FlowRule> rules = new ArrayList<>();
Saurav Das4ce45962015-11-24 23:21:05 -0800785 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800786 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800787 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
788 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
789 selector.matchInPort(pnum);
790 selector.matchVlanId(vidCriterion.vlanId());
791 selector.matchEthType(Ethernet.TYPE_IPV4);
792 selector.matchEthDst(ethCriterion.mac());
Saurav Das4ce45962015-11-24 23:21:05 -0800793 treatment.transition(UNICAST_ROUTING_TABLE);
794 FlowRule rule = DefaultFlowRule.builder()
795 .forDevice(deviceId)
796 .withSelector(selector.build())
797 .withTreatment(treatment.build())
798 .withPriority(DEFAULT_PRIORITY)
799 .fromApp(applicationId)
800 .makePermanent()
801 .forTable(TMAC_TABLE).build();
802 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800803
804 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800805 selector = DefaultTrafficSelector.builder();
806 treatment = DefaultTrafficTreatment.builder();
807 selector.matchInPort(pnum);
808 selector.matchVlanId(vidCriterion.vlanId());
809 selector.matchEthType(Ethernet.MPLS_UNICAST);
810 selector.matchEthDst(ethCriterion.mac());
Saurav Das4ce45962015-11-24 23:21:05 -0800811 treatment.transition(MPLS_TABLE_0);
812 rule = DefaultFlowRule.builder()
813 .forDevice(deviceId)
814 .withSelector(selector.build())
815 .withTreatment(treatment.build())
816 .withPriority(DEFAULT_PRIORITY)
817 .fromApp(applicationId)
818 .makePermanent()
819 .forTable(TMAC_TABLE).build();
820 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800821
822 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800823 selector = DefaultTrafficSelector.builder();
824 treatment = DefaultTrafficTreatment.builder();
825 selector.matchInPort(pnum);
826 selector.matchVlanId(vidCriterion.vlanId());
827 selector.matchEthType(Ethernet.TYPE_IPV6);
828 selector.matchEthDst(ethCriterion.mac());
Pier Ventree0ae7a32016-11-23 09:57:42 -0800829 treatment.transition(UNICAST_ROUTING_TABLE);
830 rule = DefaultFlowRule.builder()
831 .forDevice(deviceId)
832 .withSelector(selector.build())
833 .withTreatment(treatment.build())
834 .withPriority(DEFAULT_PRIORITY)
835 .fromApp(applicationId)
836 .makePermanent()
837 .forTable(TMAC_TABLE).build();
838 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800839 }
Charles Chan66291502018-03-02 16:43:28 -0800840 return ImmutableList.of(rules);
Saurav Das4ce45962015-11-24 23:21:05 -0800841 }
842
Charles Chan5270ed02016-01-30 23:22:37 -0800843 @Override
Charles Chan66291502018-03-02 16:43:28 -0800844 protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion,
Yi Tsengef19de12017-04-24 11:33:05 -0700845 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800846 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
847 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
848 selector.matchEthType(Ethernet.TYPE_IPV4);
849 selector.matchEthDst(ethCriterion.mac());
Charles Chan5270ed02016-01-30 23:22:37 -0800850 treatment.transition(UNICAST_ROUTING_TABLE);
851 FlowRule rule = DefaultFlowRule.builder()
852 .forDevice(deviceId)
853 .withSelector(selector.build())
854 .withTreatment(treatment.build())
855 .withPriority(DEFAULT_PRIORITY)
856 .fromApp(applicationId)
857 .makePermanent()
858 .forTable(TMAC_TABLE).build();
Charles Chan66291502018-03-02 16:43:28 -0800859 return ImmutableList.of(ImmutableList.of(rule));
Charles Chan5270ed02016-01-30 23:22:37 -0800860 }
861
Saurav Das4ce45962015-11-24 23:21:05 -0800862 /*
Charles Chanab591602019-01-22 17:25:04 -0800863 * Open vSwitch emulation allows MPLS ECMP.
Saurav Das4ce45962015-11-24 23:21:05 -0800864 *
865 * (non-Javadoc)
866 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
867 */
868 @Override
869 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Andrea Campanella7c977b92018-05-30 21:39:45 -0700870 if (isDoubleTagged(fwd)) {
871 return processDoubleTaggedFwd(fwd);
872 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800873 TrafficSelector selector = fwd.selector();
874 EthTypeCriterion ethType =
875 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
876 if ((ethType == null) ||
877 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800878 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
879 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800880 log.warn("processSpecific: Unsupported forwarding objective criteria"
881 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800882 fail(fwd, ObjectiveError.UNSUPPORTED);
883 return Collections.emptySet();
884 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800885 boolean defaultRule = false;
Charles Chan50d900c2018-03-02 13:26:22 -0800886 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800887 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800888 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
889
Saurav Das8a0732e2015-11-20 15:27:53 -0800890 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800891 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700892 if (ipv4Dst.isMulticast()) {
893 if (ipv4Dst.prefixLength() != 32) {
894 log.warn("Multicast specific forwarding objective can only be /32");
895 fail(fwd, ObjectiveError.BADPARAMS);
896 return ImmutableSet.of();
897 }
898 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
899 if (assignedVlan == null) {
900 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
901 fail(fwd, ObjectiveError.BADPARAMS);
902 return ImmutableSet.of();
903 }
904 filteredSelector.matchVlanId(assignedVlan);
905 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
906 forTableId = MULTICAST_ROUTING_TABLE;
907 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
908 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800909 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700910 if (ipv4Dst.prefixLength() == 0) {
911 // The entire IPV4_DST field is wildcarded intentionally
912 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700913 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700914 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700915 }
916 forTableId = UNICAST_ROUTING_TABLE;
917 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
918 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800919 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800920 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
Julia Ferguson65428c32017-08-10 18:15:24 +0000921 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
922 if (ipv6Dst.isMulticast()) {
923 if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
924 log.debug("Multicast specific IPv6 forwarding objective can only be /128");
925 fail(fwd, ObjectiveError.BADPARAMS);
926 return ImmutableSet.of();
927 }
928 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
929 if (assignedVlan == null) {
930 log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
931 fail(fwd, ObjectiveError.BADPARAMS);
932 return ImmutableSet.of();
933 }
934 filteredSelector.matchVlanId(assignedVlan);
935 filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
936 forTableId = MULTICAST_ROUTING_TABLE;
937 log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
938 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
939 } else {
940 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
941 return Collections.emptyList();
942 }
943 forTableId = UNICAST_ROUTING_TABLE;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800944 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800945 } else {
946 filteredSelector
947 .matchEthType(Ethernet.MPLS_UNICAST)
948 .matchMplsLabel(((MplsCriterion)
949 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
950 MplsBosCriterion bos = (MplsBosCriterion) selector
951 .getCriterion(Criterion.Type.MPLS_BOS);
952 if (bos != null) {
953 filteredSelector.matchMplsBos(bos.mplsBos());
954 }
955 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800956 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
957 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800958 }
959
960 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
961 if (fwd.treatment() != null) {
962 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chanab591602019-01-22 17:25:04 -0800963 if (i instanceof L3ModificationInstruction) {
Charles Chan40132b32017-01-22 00:19:37 -0800964 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
965 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
966 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
967 continue;
968 }
969 }
Charles Chan7d10b162015-12-07 18:54:45 -0800970 /*
971 * NOTE: OF-DPA does not support immediate instruction in
972 * L3 unicast and MPLS table.
973 */
974 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800975 }
976 }
977
978 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800979 NextGroup next = getGroupForNextObjective(fwd.nextId());
980 if (next != null) {
981 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
982 // we only need the top level group's key to point the flow to it
983 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
984 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700985 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
986 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800987 fail(fwd, ObjectiveError.GROUPMISSING);
988 return Collections.emptySet();
989 }
990 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800991 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800992 }
993 tb.transition(ACL_TABLE);
994 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
995 .fromApp(fwd.appId())
996 .withPriority(fwd.priority())
997 .forDevice(deviceId)
998 .withSelector(filteredSelector.build())
999 .withTreatment(tb.build())
1000 .forTable(forTableId);
1001
1002 if (fwd.permanent()) {
1003 ruleBuilder.makePermanent();
1004 } else {
1005 ruleBuilder.makeTemporary(fwd.timeout());
1006 }
Flavio Castroe10fa242016-01-15 12:43:51 -08001007 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
1008 flowRuleCollection.add(ruleBuilder.build());
1009 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -08001010 flowRuleCollection.add(
1011 defaultRoute(fwd, complementarySelector, forTableId, tb)
1012 );
Flavio Castroe10fa242016-01-15 12:43:51 -08001013 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
1014 }
Flavio Castroe10fa242016-01-15 12:43:51 -08001015 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -08001016 }
1017
Charles Chan1e492d32016-01-30 23:22:37 -08001018 @Override
1019 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
1020 List<FlowRule> rules = new ArrayList<>();
1021
1022 // Build filtered selector
1023 TrafficSelector selector = fwd.selector();
1024 EthCriterion ethCriterion = (EthCriterion) selector
1025 .getCriterion(Criterion.Type.ETH_DST);
1026 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
Andrea Campanella7c977b92018-05-30 21:39:45 -07001027 .getCriterion(VLAN_VID);
Charles Chan1e492d32016-01-30 23:22:37 -08001028
1029 if (vlanIdCriterion == null) {
1030 log.warn("Forwarding objective for bridging requires vlan. Not "
1031 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
1032 fail(fwd, ObjectiveError.BADPARAMS);
1033 return Collections.emptySet();
1034 }
1035
1036 TrafficSelector.Builder filteredSelectorBuilder =
1037 DefaultTrafficSelector.builder();
1038 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -08001039 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -08001040 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
1041 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
1042 fwd.id(), fwd.nextId(), deviceId);
1043 } else {
1044 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
1045 + "in dev:{} for vlan:{}",
1046 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
1047 }
1048 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
1049 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
1050
1051 if (fwd.treatment() != null) {
1052 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
1053 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
1054 }
1055
1056 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1057 if (fwd.nextId() != null) {
1058 NextGroup next = getGroupForNextObjective(fwd.nextId());
1059 if (next != null) {
1060 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
1061 // we only need the top level group's key to point the flow to it
1062 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
1063 if (group != null) {
1064 treatmentBuilder.deferred().group(group.id());
1065 } else {
1066 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
1067 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
1068 fail(fwd, ObjectiveError.GROUPMISSING);
1069 return Collections.emptySet();
1070 }
1071 }
1072 }
1073 treatmentBuilder.immediate().transition(ACL_TABLE);
1074 TrafficTreatment filteredTreatment = treatmentBuilder.build();
1075
1076 // Build bridging table entries
1077 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
1078 flowRuleBuilder.fromApp(fwd.appId())
1079 .withPriority(fwd.priority())
1080 .forDevice(deviceId)
1081 .withSelector(filteredSelector)
1082 .withTreatment(filteredTreatment)
1083 .forTable(BRIDGING_TABLE);
1084 if (fwd.permanent()) {
1085 flowRuleBuilder.makePermanent();
1086 } else {
1087 flowRuleBuilder.makeTemporary(fwd.timeout());
1088 }
1089 rules.add(flowRuleBuilder.build());
1090 return rules;
1091 }
1092
Saurav Das52025962016-01-28 22:30:01 -08001093 @Override
Charles Chanab591602019-01-22 17:25:04 -08001094 protected TrafficTreatment.Builder versatileTreatmentBuilder(ForwardingObjective fwd) {
Saurav Das52025962016-01-28 22:30:01 -08001095 // XXX driver does not currently do type checking as per Tables 65-67 in
1096 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
1097 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
1098 if (fwd.treatment() != null) {
1099 for (Instruction ins : fwd.treatment().allInstructions()) {
1100 if (ins instanceof OutputInstruction) {
1101 OutputInstruction o = (OutputInstruction) ins;
Charles Chanab591602019-01-22 17:25:04 -08001102 if (PortNumber.CONTROLLER.equals(o.port())) {
Charles Chan0f43e472017-02-14 14:00:16 -08001103 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -08001104 } else {
1105 log.warn("Only allowed treatments in versatile forwarding "
1106 + "objectives are punts to the controller");
1107 }
Charles Chanf76de302018-06-15 18:54:18 -07001108 } else if (ins instanceof NoActionInstruction) {
1109 // No action is allowed and nothing needs to be done
Saurav Das52025962016-01-28 22:30:01 -08001110 } else {
1111 log.warn("Cannot process instruction in versatile fwd {}", ins);
1112 }
1113 }
Charles Chan2df0e8a2017-01-09 11:45:08 -08001114 if (fwd.treatment().clearedDeferred()) {
1115 ttBuilder.wipeDeferred();
1116 }
Saurav Das52025962016-01-28 22:30:01 -08001117 }
1118 if (fwd.nextId() != null) {
Charles Chanab591602019-01-22 17:25:04 -08001119 // Override case
Saurav Das52025962016-01-28 22:30:01 -08001120 NextGroup next = getGroupForNextObjective(fwd.nextId());
Charles Chanab591602019-01-22 17:25:04 -08001121 if (next == null) {
1122 fail(fwd, ObjectiveError.BADPARAMS);
1123 return null;
1124 }
Saurav Das52025962016-01-28 22:30:01 -08001125 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
1126 // we only need the top level group's key to point the flow to it
1127 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
1128 if (group == null) {
1129 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
Charles Chanab591602019-01-22 17:25:04 -08001130 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das52025962016-01-28 22:30:01 -08001131 fail(fwd, ObjectiveError.GROUPMISSING);
Charles Chanab591602019-01-22 17:25:04 -08001132 return null;
Saurav Das52025962016-01-28 22:30:01 -08001133 }
1134 ttBuilder.deferred().group(group.id());
1135 }
Charles Chanab591602019-01-22 17:25:04 -08001136 return ttBuilder;
Saurav Das52025962016-01-28 22:30:01 -08001137 }
1138
1139 /*
Charles Chanab591602019-01-22 17:25:04 -08001140 * Open vSwitch emulation requires table-miss-entries in forwarding tables.
Saurav Das52025962016-01-28 22:30:01 -08001141 * Real OFDPA does not require these rules as they are put in by default.
1142 *
1143 * (non-Javadoc)
1144 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
1145 */
Saurav Das2857f382015-11-03 14:39:27 -08001146 @Override
Saurav Das558afec2015-05-31 17:12:48 -07001147 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -08001148 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
1149 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
Andrea Campanella7c977b92018-05-30 21:39:45 -07001150 initTableMiss(VLAN_1_TABLE, ACL_TABLE, null);
Charles Chanf6ec1532017-02-08 16:10:40 -08001151 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
1152 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
1153 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
Andrea Campanella7c977b92018-05-30 21:39:45 -07001154 initTableMiss(EGRESS_VLAN_FLOW_TABLE_IN_INGRESS, ACL_TABLE, null);
1155 initTableMiss(UNICAST_ROUTING_TABLE_1, ACL_TABLE, null);
Charles Chanf6ec1532017-02-08 16:10:40 -08001156 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
1157 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
1158 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
1159 initTableMiss(ACL_TABLE, -1, null);
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001160 linkDiscoveryPuntTableRules();
Charles Chan0f43e472017-02-14 14:00:16 -08001161
Charles Chanab591602019-01-22 17:25:04 -08001162 initPopVlanPuntGroup();
Saurav Das558afec2015-05-31 17:12:48 -07001163 }
1164
Charles Chanf6ec1532017-02-08 16:10:40 -08001165 /**
1166 * Install table-miss flow entry.
1167 *
1168 * If treatment exists, use it directly.
1169 * Else if treatment does not exist but nextTable > 0, transit to next table.
1170 * Else apply empty treatment.
1171 *
1172 * @param thisTable this table ID
1173 * @param nextTable next table ID
1174 * @param treatment traffic treatment to apply.
1175 */
1176 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -07001177 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -08001178 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -07001179
Charles Chanf6ec1532017-02-08 16:10:40 -08001180 if (treatment == null) {
1181 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1182 if (nextTable > 0) {
1183 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -07001184 }
Charles Chanf6ec1532017-02-08 16:10:40 -08001185 treatment = tBuilder.build();
1186 }
Saurav Das558afec2015-05-31 17:12:48 -07001187
Charles Chanb7504392017-02-10 12:51:04 -08001188 FlowRule rule = DefaultFlowRule.builder()
1189 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -08001190 .withSelector(selector)
1191 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -08001192 .withPriority(LOWEST_PRIORITY)
1193 .fromApp(driverId)
1194 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -08001195 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -08001196 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -08001197
1198 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1199 @Override
1200 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -08001201 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -08001202 }
Saurav Das2857f382015-11-03 14:39:27 -08001203 @Override
1204 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -08001205 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -08001206 }
1207 }));
1208 }
Charles Chan0f43e472017-02-14 14:00:16 -08001209
1210 /**
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001211 * Install lldp/bbdp matching rules at table PUNT_TABLE
1212 * that forward traffic to controller.
1213 *
1214 */
1215 private void linkDiscoveryPuntTableRules() {
1216 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1217 TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build();
1218
1219 TrafficSelector.Builder lldpSelector = DefaultTrafficSelector.builder();
1220 lldpSelector.matchEthType(EthType.EtherType.LLDP.ethType().toShort());
1221 FlowRule lldpRule = DefaultFlowRule.builder()
1222 .forDevice(deviceId)
1223 .withSelector(lldpSelector.build())
1224 .withTreatment(treatment)
1225 .withPriority(HIGHEST_PRIORITY)
1226 .fromApp(driverId)
1227 .makePermanent()
1228 .forTable(PUNT_TABLE).build();
1229 ops = ops.add(lldpRule);
1230
1231 TrafficSelector.Builder bbdpSelector = DefaultTrafficSelector.builder();
1232 bbdpSelector.matchEthType(EthType.EtherType.BDDP.ethType().toShort());
1233 FlowRule bbdpRule = DefaultFlowRule.builder()
1234 .forDevice(deviceId)
1235 .withSelector(bbdpSelector.build())
1236 .withTreatment(treatment)
1237 .withPriority(HIGHEST_PRIORITY)
1238 .fromApp(driverId)
1239 .makePermanent()
1240 .forTable(PUNT_TABLE).build();
1241 ops.add(bbdpRule);
1242
1243 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1244 @Override
1245 public void onSuccess(FlowRuleOperations ops) {
1246 log.info("Added lldp/bbdp rules for table {} on {}", PUNT_TABLE, deviceId);
1247 }
1248 @Override
1249 public void onError(FlowRuleOperations ops) {
1250 log.warn("Failed to initialize lldp/bbdp rules for table {} on {}", PUNT_TABLE, deviceId);
1251 }
1252 }));
1253 }
1254
1255 /**
Charles Chan0f43e472017-02-14 14:00:16 -08001256 * Builds a indirect group contains pop_vlan and punt actions.
1257 * <p>
1258 * Using group instead of immediate action to ensure that
1259 * the copy of packet on the data plane is not affected by the pop vlan action.
1260 */
1261 private void initPopVlanPuntGroup() {
Yi Tsengef19de12017-04-24 11:33:05 -07001262 GroupKey groupKey = popVlanPuntGroupKey();
Charles Chan0f43e472017-02-14 14:00:16 -08001263 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
1264 .popVlan().punt().build();
1265 GroupBucket bucket =
1266 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
1267 GroupDescription groupDesc =
1268 new DefaultGroupDescription(
1269 deviceId,
1270 GroupDescription.Type.INDIRECT,
1271 new GroupBuckets(Collections.singletonList(bucket)),
1272 groupKey,
1273 POP_VLAN_PUNT_GROUP_ID,
1274 driverId);
1275 groupService.addGroup(groupDesc);
1276
1277 log.info("Initialized pop vlan punt group on {}", deviceId);
1278 }
Yi Tsengef19de12017-04-24 11:33:05 -07001279
1280 /**
1281 * Generates group key for a static indirect group that pop vlan and punt to
1282 * controller.
1283 *
1284 * @return the group key of the indirect table
1285 */
1286 private GroupKey popVlanPuntGroupKey() {
Charles Chan367c1c12018-10-19 16:23:28 -07001287 int hash = POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_NIBBLE_MASK);
Yi Tsengef19de12017-04-24 11:33:05 -07001288 return new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(hash));
1289 }
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001290
1291 private class PopVlanPuntGroupChecker implements Runnable {
1292 @Override
1293 public void run() {
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001294 try {
1295 groupCheckerLock.lock();
1296 // this can happen outside of the lock but I think it is safer
1297 // to include it here.
1298 Group group = groupService.getGroup(deviceId, popVlanPuntGroupKey());
Charles Chan4a288d92019-02-16 00:11:18 +00001299 if (group != null) {
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001300 log.debug("PopVlanPuntGroupChecker: Installing {} missing rules at punt table.",
1301 flowRuleQueue.size());
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001302
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001303 // if we have pending flow rules install them
1304 if (flowRuleQueue.size() > 0) {
1305 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1306 // we should not care about the context here, it can only be add
1307 // since when removing the rules the group should be there already.
1308 flowRuleQueue.forEach(ops::add);
1309 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1310 @Override
1311 public void onSuccess(FlowRuleOperations ops) {
1312 log.debug("Applied {} pop vlan punt rules in device {}",
1313 ops.stages().get(0).size(), deviceId);
1314 }
1315
1316 @Override
1317 public void onError(FlowRuleOperations ops) {
1318 log.error("Failed to apply all pop vlan punt rules in dev {}", deviceId);
1319 }
1320 }));
1321 }
1322 // this signifies that the group is created and now
1323 // flow rules can be installed directly
1324 flowRuleQueue = null;
1325 // shutdown the group checker gracefully
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001326 groupChecker.shutdown();
1327 }
Andreas Pantelopoulos470865e2018-06-04 15:10:35 -07001328 } finally {
1329 groupCheckerLock.unlock();
Andreas Pantelopoulos89369462018-05-30 14:30:24 -07001330 }
1331 }
1332 }
Saurav Das558afec2015-05-31 17:12:48 -07001333}