blob: a12b76fb74ce13551cc0fb1253cd9f11221e5eec [file] [log] [blame]
Saurav Das822c4e22015-10-23 10:51:11 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Saurav Das822c4e22015-10-23 10:51:11 -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 */
16package org.onosproject.driver.pipeline;
17
Charles Chan5270ed02016-01-30 23:22:37 -080018import com.google.common.collect.ImmutableList;
Charles Chan5b9df8d2016-03-28 22:21:40 -070019import com.google.common.collect.ImmutableSet;
Saurav Das822c4e22015-10-23 10:51:11 -070020import org.onlab.osgi.ServiceDirectory;
Saurav Das822c4e22015-10-23 10:51:11 -070021import org.onlab.packet.Ethernet;
Charles Chan14967c22015-12-07 11:11:50 -080022import org.onlab.packet.IpPrefix;
Saurav Das822c4e22015-10-23 10:51:11 -070023import org.onlab.packet.VlanId;
24import org.onlab.util.KryoNamespace;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
Charles Chancad338a2016-09-16 18:03:11 -070027import org.onosproject.driver.extensions.Ofdpa3MplsType;
28import org.onosproject.driver.extensions.Ofdpa3SetMplsType;
Charles Chan14967c22015-12-07 11:11:50 -080029import org.onosproject.driver.extensions.OfdpaMatchVlanVid;
30import org.onosproject.driver.extensions.OfdpaSetVlanVid;
Saurav Das822c4e22015-10-23 10:51:11 -070031import org.onosproject.net.DeviceId;
32import org.onosproject.net.Port;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.behaviour.NextGroup;
35import org.onosproject.net.behaviour.Pipeliner;
36import org.onosproject.net.behaviour.PipelinerContext;
37import org.onosproject.net.device.DeviceService;
38import org.onosproject.net.driver.AbstractHandlerBehaviour;
39import org.onosproject.net.flow.DefaultFlowRule;
40import org.onosproject.net.flow.DefaultTrafficSelector;
41import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.FlowRule;
43import org.onosproject.net.flow.FlowRuleOperations;
44import org.onosproject.net.flow.FlowRuleOperationsContext;
45import org.onosproject.net.flow.FlowRuleService;
46import org.onosproject.net.flow.TrafficSelector;
47import org.onosproject.net.flow.TrafficTreatment;
48import org.onosproject.net.flow.criteria.Criteria;
49import org.onosproject.net.flow.criteria.Criterion;
50import org.onosproject.net.flow.criteria.EthCriterion;
51import org.onosproject.net.flow.criteria.EthTypeCriterion;
Charles Chan14967c22015-12-07 11:11:50 -080052import org.onosproject.net.flow.criteria.ExtensionCriterion;
Saurav Das822c4e22015-10-23 10:51:11 -070053import org.onosproject.net.flow.criteria.IPCriterion;
Pier Ventree0ae7a32016-11-23 09:57:42 -080054import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion;
55import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080056import org.onosproject.net.flow.criteria.MplsBosCriterion;
57import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das822c4e22015-10-23 10:51:11 -070058import org.onosproject.net.flow.criteria.PortCriterion;
59import org.onosproject.net.flow.criteria.VlanIdCriterion;
60import org.onosproject.net.flow.instructions.Instruction;
61import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
62import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Saurav Das8a0732e2015-11-20 15:27:53 -080063import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
Saurav Das822c4e22015-10-23 10:51:11 -070064import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
Charles Chan14967c22015-12-07 11:11:50 -080065import org.onosproject.net.flow.instructions.L3ModificationInstruction;
66import org.onosproject.net.flow.instructions.L3ModificationInstruction.L3SubType;
Saurav Das822c4e22015-10-23 10:51:11 -070067import org.onosproject.net.flowobjective.FilteringObjective;
68import org.onosproject.net.flowobjective.FlowObjectiveStore;
69import org.onosproject.net.flowobjective.ForwardingObjective;
70import org.onosproject.net.flowobjective.NextObjective;
71import org.onosproject.net.flowobjective.Objective;
72import org.onosproject.net.flowobjective.ObjectiveError;
Saurav Das822c4e22015-10-23 10:51:11 -070073import org.onosproject.net.group.DefaultGroupKey;
74import org.onosproject.net.group.Group;
Saurav Das822c4e22015-10-23 10:51:11 -070075import org.onosproject.net.group.GroupKey;
Saurav Das822c4e22015-10-23 10:51:11 -070076import org.onosproject.net.group.GroupService;
Saurav Das822c4e22015-10-23 10:51:11 -070077import org.onosproject.store.serializers.KryoNamespaces;
78import org.slf4j.Logger;
79
Pier Ventree0ae7a32016-11-23 09:57:42 -080080import java.util.ArrayDeque;
81import java.util.ArrayList;
82import java.util.Collection;
83import java.util.Collections;
84import java.util.Deque;
85import java.util.List;
86import java.util.Objects;
87import java.util.Set;
88import java.util.concurrent.ConcurrentHashMap;
89import java.util.concurrent.ScheduledExecutorService;
90import java.util.concurrent.TimeUnit;
91
92import static java.util.concurrent.Executors.newScheduledThreadPool;
Yi Tseng3a77b4f2017-02-06 15:02:17 -080093import static org.onlab.packet.MacAddress.BROADCAST;
94import static org.onlab.packet.MacAddress.NONE;
Pier Ventree0ae7a32016-11-23 09:57:42 -080095import static org.onlab.util.Tools.groupedThreads;
96import static org.slf4j.LoggerFactory.getLogger;
97
Saurav Das822c4e22015-10-23 10:51:11 -070098/**
99 * Driver for Broadcom's OF-DPA v2.0 TTP.
100 *
101 */
Charles Chan361154b2016-03-24 10:23:39 -0700102public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeliner {
Saurav Das822c4e22015-10-23 10:51:11 -0700103 protected static final int PORT_TABLE = 0;
104 protected static final int VLAN_TABLE = 10;
105 protected static final int TMAC_TABLE = 20;
106 protected static final int UNICAST_ROUTING_TABLE = 30;
107 protected static final int MULTICAST_ROUTING_TABLE = 40;
108 protected static final int MPLS_TABLE_0 = 23;
109 protected static final int MPLS_TABLE_1 = 24;
Charles Chancad338a2016-09-16 18:03:11 -0700110 protected static final int MPLS_L3_TYPE = 27;
Saurav Das822c4e22015-10-23 10:51:11 -0700111 protected static final int BRIDGING_TABLE = 50;
112 protected static final int ACL_TABLE = 60;
113 protected static final int MAC_LEARNING_TABLE = 254;
114 protected static final long OFPP_MAX = 0xffffff00L;
115
Saurav Das52025962016-01-28 22:30:01 -0800116 protected static final int HIGHEST_PRIORITY = 0xffff;
Saurav Das2857f382015-11-03 14:39:27 -0800117 protected static final int DEFAULT_PRIORITY = 0x8000;
Saurav Das822c4e22015-10-23 10:51:11 -0700118 protected static final int LOWEST_PRIORITY = 0x0;
119
Saurav Das822c4e22015-10-23 10:51:11 -0700120 private final Logger log = getLogger(getClass());
Charles Chan425854b2016-04-11 15:32:12 -0700121 protected ServiceDirectory serviceDirectory;
Saurav Das822c4e22015-10-23 10:51:11 -0700122 protected FlowRuleService flowRuleService;
Charles Chan425854b2016-04-11 15:32:12 -0700123 protected CoreService coreService;
Saurav Das8a0732e2015-11-20 15:27:53 -0800124 protected GroupService groupService;
125 protected FlowObjectiveStore flowObjectiveStore;
Saurav Das822c4e22015-10-23 10:51:11 -0700126 protected DeviceId deviceId;
127 protected ApplicationId driverId;
Saurav Das822c4e22015-10-23 10:51:11 -0700128 protected DeviceService deviceService;
Charles Chan188ebf52015-12-23 00:15:11 -0800129 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
Saurav Das822c4e22015-10-23 10:51:11 -0700130 .register(KryoNamespaces.API)
131 .register(GroupKey.class)
132 .register(DefaultGroupKey.class)
Charles Chan361154b2016-03-24 10:23:39 -0700133 .register(Ofdpa2GroupHandler.OfdpaNextGroup.class)
Saurav Das8a0732e2015-11-20 15:27:53 -0800134 .register(ArrayDeque.class)
Charles Chaneefdedf2016-05-23 16:45:45 -0700135 .build("Ofdpa2Pipeline");
Saurav Das822c4e22015-10-23 10:51:11 -0700136
Charles Chan425854b2016-04-11 15:32:12 -0700137 protected Ofdpa2GroupHandler groupHandler;
Saurav Das822c4e22015-10-23 10:51:11 -0700138
Saurav Das52025962016-01-28 22:30:01 -0800139 protected Set<IPCriterion> sentIpFilters = Collections.newSetFromMap(
Charles Chan188ebf52015-12-23 00:15:11 -0800140 new ConcurrentHashMap<>());
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700141 // flows installations to be retried
142 protected ScheduledExecutorService executorService
143 = newScheduledThreadPool(5, groupedThreads("OfdpaPipeliner", "retry-%d", log));
144 protected static final int MAX_RETRY_ATTEMPTS = 10;
145 protected static final int RETRY_MS = 1000;
Saurav Das4f980082015-11-05 13:39:15 -0800146
Saurav Das822c4e22015-10-23 10:51:11 -0700147 @Override
148 public void init(DeviceId deviceId, PipelinerContext context) {
Saurav Das822c4e22015-10-23 10:51:11 -0700149 this.deviceId = deviceId;
150
Charles Chan425854b2016-04-11 15:32:12 -0700151 serviceDirectory = context.directory();
Saurav Das822c4e22015-10-23 10:51:11 -0700152 coreService = serviceDirectory.get(CoreService.class);
153 flowRuleService = serviceDirectory.get(FlowRuleService.class);
154 groupService = serviceDirectory.get(GroupService.class);
155 flowObjectiveStore = context.store();
Saurav Das822c4e22015-10-23 10:51:11 -0700156 deviceService = serviceDirectory.get(DeviceService.class);
Saurav Das822c4e22015-10-23 10:51:11 -0700157
Charles Chan40132b32017-01-22 00:19:37 -0800158 initDriverId();
159 initGroupHander(context);
Saurav Das822c4e22015-10-23 10:51:11 -0700160
Saurav Das822c4e22015-10-23 10:51:11 -0700161 initializePipeline();
Saurav Das822c4e22015-10-23 10:51:11 -0700162 }
163
Charles Chan40132b32017-01-22 00:19:37 -0800164 protected void initDriverId() {
165 driverId = coreService.registerApplication(
166 "org.onosproject.driver.Ofdpa2Pipeline");
167 }
168
169 protected void initGroupHander(PipelinerContext context) {
170 groupHandler = new Ofdpa2GroupHandler();
171 groupHandler.init(deviceId, context);
172 }
173
Saurav Das822c4e22015-10-23 10:51:11 -0700174 protected void initializePipeline() {
Charles Chan188ebf52015-12-23 00:15:11 -0800175 // OF-DPA does not require initializing the pipeline as it puts default
176 // rules automatically in the hardware. However emulation of OFDPA in
177 // software switches does require table-miss-entries.
Saurav Das822c4e22015-10-23 10:51:11 -0700178 }
179
180 //////////////////////////////////////
181 // Flow Objectives
182 //////////////////////////////////////
183
184 @Override
185 public void filter(FilteringObjective filteringObjective) {
186 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
187 processFilter(filteringObjective,
188 filteringObjective.op() == Objective.Operation.ADD,
189 filteringObjective.appId());
190 } else {
191 // Note that packets that don't match the PERMIT filter are
192 // automatically denied. The DENY filter is used to deny packets
193 // that are otherwise permitted by the PERMIT filter.
194 // Use ACL table flow rules here for DENY filtering objectives
195 log.debug("filter objective other than PERMIT currently not supported");
196 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
197 }
198 }
199
200 @Override
201 public void forward(ForwardingObjective fwd) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700202 Collection<FlowRule> rules = processForward(fwd);
Saurav Das25190812016-05-27 13:54:07 -0700203 if (rules == null || rules.isEmpty()) {
204 // Assumes fail message has already been generated to the objective
205 // context. Returning here prevents spurious pass message to be
206 // generated by FlowRule service for empty flowOps.
207 return;
208 }
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700209 sendForward(fwd, rules);
210 }
211
212 protected void sendForward(ForwardingObjective fwd, Collection<FlowRule> rules) {
213 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
Saurav Das822c4e22015-10-23 10:51:11 -0700214 switch (fwd.op()) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700215 case ADD:
216 rules.stream()
217 .filter(Objects::nonNull)
218 .forEach(flowOpsBuilder::add);
Saurav Dasd2fded02016-12-02 15:43:47 -0800219 log.debug("Applying a add fwd-obj {} to sw:{}", fwd.id(), deviceId);
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700220 break;
221 case REMOVE:
222 rules.stream()
223 .filter(Objects::nonNull)
224 .forEach(flowOpsBuilder::remove);
225 break;
226 default:
227 fail(fwd, ObjectiveError.UNKNOWN);
228 log.warn("Unknown forwarding type {}", fwd.op());
Saurav Das822c4e22015-10-23 10:51:11 -0700229 }
230
Saurav Das822c4e22015-10-23 10:51:11 -0700231 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
232 @Override
233 public void onSuccess(FlowRuleOperations ops) {
234 pass(fwd);
235 }
236
237 @Override
238 public void onError(FlowRuleOperations ops) {
239 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
240 }
241 }));
Saurav Das822c4e22015-10-23 10:51:11 -0700242 }
243
244 @Override
245 public void next(NextObjective nextObjective) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800246 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
247 switch (nextObjective.op()) {
248 case ADD:
Saurav Das4f980082015-11-05 13:39:15 -0800249 if (nextGroup != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800250 log.warn("Cannot add next {} that already exists in device {}",
251 nextObjective.id(), deviceId);
252 return;
253 }
254 log.debug("Processing NextObjective id{} in dev{} - add group",
255 nextObjective.id(), deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700256 groupHandler.addGroup(nextObjective);
Saurav Das8a0732e2015-11-20 15:27:53 -0800257 break;
258 case ADD_TO_EXISTING:
259 if (nextGroup != null) {
260 log.debug("Processing NextObjective id{} in dev{} - add bucket",
261 nextObjective.id(), deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700262 groupHandler.addBucketToGroup(nextObjective, nextGroup);
Saurav Das4f980082015-11-05 13:39:15 -0800263 } else {
Saurav Das8a0732e2015-11-20 15:27:53 -0800264 // it is possible that group-chain has not been fully created yet
Saurav Das423fe2b2015-12-04 10:52:59 -0800265 log.debug("Waiting to add bucket to group for next-id:{} in dev:{}",
266 nextObjective.id(), deviceId);
267 // by design only one pending bucket is allowed for the group
Charles Chan425854b2016-04-11 15:32:12 -0700268 groupHandler.pendingBuckets.put(nextObjective.id(), nextObjective);
Saurav Das4f980082015-11-05 13:39:15 -0800269 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800270 break;
271 case REMOVE:
272 if (nextGroup == null) {
273 log.warn("Cannot remove next {} that does not exist in device {}",
274 nextObjective.id(), deviceId);
275 return;
276 }
277 log.debug("Processing NextObjective id{} in dev{} - remove group",
278 nextObjective.id(), deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700279 groupHandler.removeGroup(nextObjective, nextGroup);
Saurav Das8a0732e2015-11-20 15:27:53 -0800280 break;
281 case REMOVE_FROM_EXISTING:
282 if (nextGroup == null) {
283 log.warn("Cannot remove from next {} that does not exist in device {}",
284 nextObjective.id(), deviceId);
285 return;
286 }
287 log.debug("Processing NextObjective id{} in dev{} - remove bucket",
288 nextObjective.id(), deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700289 groupHandler.removeBucketFromGroup(nextObjective, nextGroup);
Saurav Das8a0732e2015-11-20 15:27:53 -0800290 break;
291 default:
Saurav Das4f980082015-11-05 13:39:15 -0800292 log.warn("Unsupported operation {}", nextObjective.op());
Saurav Das822c4e22015-10-23 10:51:11 -0700293 }
294 }
295
296 //////////////////////////////////////
297 // Flow handling
298 //////////////////////////////////////
299
300 /**
301 * As per OFDPA 2.0 TTP, filtering of VLAN ids, MAC addresses (for routing)
302 * and IP addresses configured on switch ports happen in different tables.
303 * Note that IP filtering rules need to be added to the ACL table, as there
304 * is no mechanism to send to controller via IP table.
305 *
306 * @param filt the filtering objective
307 * @param install indicates whether to add or remove the objective
308 * @param applicationId the application that sent this objective
309 */
Saurav Das52025962016-01-28 22:30:01 -0800310 protected void processFilter(FilteringObjective filt,
311 boolean install, ApplicationId applicationId) {
Saurav Das822c4e22015-10-23 10:51:11 -0700312 // This driver only processes filtering criteria defined with switch
313 // ports as the key
314 PortCriterion portCriterion = null;
315 EthCriterion ethCriterion = null;
316 VlanIdCriterion vidCriterion = null;
317 Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
318 if (!filt.key().equals(Criteria.dummy()) &&
319 filt.key().type() == Criterion.Type.IN_PORT) {
320 portCriterion = (PortCriterion) filt.key();
321 } else {
322 log.warn("No key defined in filtering objective from app: {}. Not"
323 + "processing filtering objective", applicationId);
Saurav Das59232cf2016-04-27 18:35:50 -0700324 fail(filt, ObjectiveError.BADPARAMS);
Saurav Das822c4e22015-10-23 10:51:11 -0700325 return;
326 }
Saurav Das59232cf2016-04-27 18:35:50 -0700327 log.debug("Received filtering objective for dev/port: {}/{}", deviceId,
328 portCriterion.port());
Saurav Das822c4e22015-10-23 10:51:11 -0700329 // convert filtering conditions for switch-intfs into flowrules
330 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
331 for (Criterion criterion : filt.conditions()) {
Charles Chan5b9df8d2016-03-28 22:21:40 -0700332 if (criterion.type() == Criterion.Type.ETH_DST ||
333 criterion.type() == Criterion.Type.ETH_DST_MASKED) {
Saurav Das822c4e22015-10-23 10:51:11 -0700334 ethCriterion = (EthCriterion) criterion;
335 } else if (criterion.type() == Criterion.Type.VLAN_VID) {
336 vidCriterion = (VlanIdCriterion) criterion;
337 } else if (criterion.type() == Criterion.Type.IPV4_DST) {
338 ips.add((IPCriterion) criterion);
339 } else {
340 log.error("Unsupported filter {}", criterion);
341 fail(filt, ObjectiveError.UNSUPPORTED);
342 return;
343 }
344 }
345
Saurav Das0e99e2b2015-10-28 12:39:42 -0700346 VlanId assignedVlan = null;
Charles Chane849c192016-01-11 18:28:54 -0800347 if (vidCriterion != null) {
Charles Chand55e84d2016-03-30 17:54:24 -0700348 // Use the VLAN in metadata whenever a metadata is provided
349 if (filt.meta() != null) {
350 assignedVlan = readVlanFromTreatment(filt.meta());
351 // Use the VLAN in criterion if metadata is not present and the traffic is tagged
352 } else if (!vidCriterion.vlanId().equals(VlanId.NONE)) {
Charles Chane849c192016-01-11 18:28:54 -0800353 assignedVlan = vidCriterion.vlanId();
Charles Chand55e84d2016-03-30 17:54:24 -0700354 }
Charles Chane849c192016-01-11 18:28:54 -0800355
Charles Chand55e84d2016-03-30 17:54:24 -0700356 if (assignedVlan == null) {
357 log.error("Driver fails to extract VLAN information. "
358 + "Not proccessing VLAN filters on device {}.", deviceId);
359 log.debug("VLAN ID in criterion={}, metadata={}",
360 readVlanFromTreatment(filt.meta()), vidCriterion.vlanId());
361 fail(filt, ObjectiveError.BADPARAMS);
362 return;
Saurav Das0e99e2b2015-10-28 12:39:42 -0700363 }
364 }
365
Yi Tseng3a77b4f2017-02-06 15:02:17 -0800366 if (ethCriterion == null || ethCriterion.mac().equals(NONE)) {
Charles Chan985b12e2016-05-11 19:47:22 -0700367 // NOTE: it is possible that a filtering objective only has vidCriterion
368 log.debug("filtering objective missing dstMac, cannot program TMAC table");
Saurav Das822c4e22015-10-23 10:51:11 -0700369 } else {
370 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700371 vidCriterion, assignedVlan,
372 applicationId)) {
Saurav Das822c4e22015-10-23 10:51:11 -0700373 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
374 tmacRule, deviceId);
375 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
376 }
377 }
378
Charles Chan985b12e2016-05-11 19:47:22 -0700379 if (vidCriterion == null) {
380 // NOTE: it is possible that a filtering objective only has ethCriterion
381 log.debug("filtering objective missing dstMac or VLAN, "
Charles Chane849c192016-01-11 18:28:54 -0800382 + "cannot program VLAN Table");
Saurav Das822c4e22015-10-23 10:51:11 -0700383 } else {
Charles Chan14967c22015-12-07 11:11:50 -0800384 /*
385 * NOTE: Separate vlan filtering rules and assignment rules
386 * into different stage in order to guarantee that filtering rules
Saurav Das52025962016-01-28 22:30:01 -0800387 * always go first, as required by ofdpa.
Charles Chan14967c22015-12-07 11:11:50 -0800388 */
389 List<FlowRule> allRules = processVlanIdFilter(
390 portCriterion, vidCriterion, assignedVlan, applicationId);
391 List<FlowRule> filteringRules = new ArrayList<>();
392 List<FlowRule> assignmentRules = new ArrayList<>();
393
394 allRules.forEach(flowRule -> {
395 ExtensionCriterion extCriterion =
396 (ExtensionCriterion) flowRule.selector().getCriterion(Criterion.Type.EXTENSION);
397 VlanId vlanId = ((OfdpaMatchVlanVid) extCriterion.extensionSelector()).vlanId();
Charles Chanbe8aea42016-02-24 12:04:47 -0800398 if (!vlanId.equals(VlanId.NONE)) {
Charles Chan14967c22015-12-07 11:11:50 -0800399 filteringRules.add(flowRule);
400 } else {
401 assignmentRules.add(flowRule);
402 }
403 });
404
405 for (FlowRule filteringRule : filteringRules) {
Saurav Das822c4e22015-10-23 10:51:11 -0700406 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
Charles Chan14967c22015-12-07 11:11:50 -0800407 filteringRule, deviceId);
408 ops = install ? ops.add(filteringRule) : ops.remove(filteringRule);
409 }
410
411 ops.newStage();
412
413 for (FlowRule assignmentRule : assignmentRules) {
414 log.debug("adding VLAN assignment rule in VLAN table: {} for dev: {}",
415 assignmentRule, deviceId);
416 ops = install ? ops.add(assignmentRule) : ops.remove(assignmentRule);
Saurav Das822c4e22015-10-23 10:51:11 -0700417 }
418 }
419
420 for (IPCriterion ipaddr : ips) {
421 // since we ignore port information for IP rules, and the same (gateway) IP
422 // can be configured on multiple ports, we make sure that we send
423 // only a single rule to the switch.
424 if (!sentIpFilters.contains(ipaddr)) {
425 sentIpFilters.add(ipaddr);
426 log.debug("adding IP filtering rules in ACL table {} for dev: {}",
427 ipaddr, deviceId);
428 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
429 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
430 selector.matchEthType(Ethernet.TYPE_IPV4);
431 selector.matchIPDst(ipaddr.ip());
432 treatment.setOutput(PortNumber.CONTROLLER);
433 FlowRule rule = DefaultFlowRule.builder()
434 .forDevice(deviceId)
435 .withSelector(selector.build())
436 .withTreatment(treatment.build())
437 .withPriority(HIGHEST_PRIORITY)
438 .fromApp(applicationId)
439 .makePermanent()
440 .forTable(ACL_TABLE).build();
441 ops = install ? ops.add(rule) : ops.remove(rule);
442 }
443 }
444
445 // apply filtering flow rules
446 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
447 @Override
448 public void onSuccess(FlowRuleOperations ops) {
449 log.info("Applied {} filtering rules in device {}",
450 ops.stages().get(0).size(), deviceId);
451 pass(filt);
452 }
453
454 @Override
455 public void onError(FlowRuleOperations ops) {
456 log.info("Failed to apply all filtering rules in dev {}", deviceId);
457 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
458 }
459 }));
460
461 }
462
463 /**
464 * Allows untagged packets into pipeline by assigning a vlan id.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700465 * Vlan assignment is done by the application.
Saurav Das822c4e22015-10-23 10:51:11 -0700466 * Allows tagged packets into pipeline as per configured port-vlan info.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700467 *
Charles Chanf9e98652016-09-07 16:54:23 -0700468 * @param portCriterion port on device for which this filter is programmed
469 * @param vidCriterion vlan assigned to port, or NONE for untagged
470 * @param assignedVlan assigned vlan-id for untagged packets
471 * @param applicationId for application programming this filter
Saurav Das822c4e22015-10-23 10:51:11 -0700472 * @return list of FlowRule for port-vlan filters
473 */
474 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
475 VlanIdCriterion vidCriterion,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700476 VlanId assignedVlan,
Saurav Das822c4e22015-10-23 10:51:11 -0700477 ApplicationId applicationId) {
Charles Chanf9e98652016-09-07 16:54:23 -0700478 return processVlanIdFilterInternal(portCriterion, vidCriterion, assignedVlan,
479 applicationId, true);
480 }
481
482 /**
483 * Internal implementation of processVlanIdFilter.
484 * <p>
485 * The is_present bit in set_vlan_vid action is required to be 0 in OFDPA i12.
486 * Since it is non-OF spec, we need an extension treatment for that.
487 * The useSetVlanExtension must be set to false for OFDPA i12.
488 * </p>
489 *
490 * @param portCriterion port on device for which this filter is programmed
491 * @param vidCriterion vlan assigned to port, or NONE for untagged
492 * @param assignedVlan assigned vlan-id for untagged packets
493 * @param applicationId for application programming this filter
494 * @param useSetVlanExtension use the setVlanVid extension that has is_present bit set to 0.
495 * @return list of FlowRule for port-vlan filters
496 */
497 protected List<FlowRule> processVlanIdFilterInternal(PortCriterion portCriterion,
498 VlanIdCriterion vidCriterion,
499 VlanId assignedVlan,
500 ApplicationId applicationId,
501 boolean useSetVlanExtension) {
Charles Chan14967c22015-12-07 11:11:50 -0800502 List<FlowRule> rules = new ArrayList<>();
Saurav Das822c4e22015-10-23 10:51:11 -0700503 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
504 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Charles Chan14967c22015-12-07 11:11:50 -0800505 TrafficSelector.Builder preSelector = null;
506 TrafficTreatment.Builder preTreatment = null;
507
Saurav Das4f980082015-11-05 13:39:15 -0800508 treatment.transition(TMAC_TABLE);
509
Saurav Das822c4e22015-10-23 10:51:11 -0700510 if (vidCriterion.vlanId() == VlanId.NONE) {
511 // untagged packets are assigned vlans
Charles Chanbe8aea42016-02-24 12:04:47 -0800512 OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(VlanId.NONE);
Charles Chan14967c22015-12-07 11:11:50 -0800513 selector.extension(ofdpaMatchVlanVid, deviceId);
Charles Chanf9e98652016-09-07 16:54:23 -0700514 if (useSetVlanExtension) {
515 OfdpaSetVlanVid ofdpaSetVlanVid = new OfdpaSetVlanVid(assignedVlan);
516 treatment.extension(ofdpaSetVlanVid, deviceId);
517 } else {
518 treatment.setVlanId(assignedVlan);
519 }
Charles Chan14967c22015-12-07 11:11:50 -0800520
521 preSelector = DefaultTrafficSelector.builder();
522 OfdpaMatchVlanVid preOfdpaMatchVlanVid = new OfdpaMatchVlanVid(assignedVlan);
523 preSelector.extension(preOfdpaMatchVlanVid, deviceId);
524 preTreatment = DefaultTrafficTreatment.builder().transition(TMAC_TABLE);
525
Saurav Das4f980082015-11-05 13:39:15 -0800526 } else {
Charles Chan14967c22015-12-07 11:11:50 -0800527 OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(vidCriterion.vlanId());
528 selector.extension(ofdpaMatchVlanVid, deviceId);
Charles Chand55e84d2016-03-30 17:54:24 -0700529
530 if (!assignedVlan.equals(vidCriterion.vlanId())) {
Charles Chanc03782d2017-01-31 13:57:55 -0800531 if (useSetVlanExtension) {
532 OfdpaSetVlanVid ofdpaSetVlanVid = new OfdpaSetVlanVid(assignedVlan);
533 treatment.extension(ofdpaSetVlanVid, deviceId);
534 } else {
535 treatment.setVlanId(assignedVlan);
536 }
Charles Chand55e84d2016-03-30 17:54:24 -0700537 }
Saurav Das822c4e22015-10-23 10:51:11 -0700538 }
Saurav Das822c4e22015-10-23 10:51:11 -0700539
540 // ofdpa cannot match on ALL portnumber, so we need to use separate
541 // rules for each port.
Charles Chan14967c22015-12-07 11:11:50 -0800542 List<PortNumber> portnums = new ArrayList<>();
Saurav Das822c4e22015-10-23 10:51:11 -0700543 if (portCriterion.port() == PortNumber.ALL) {
544 for (Port port : deviceService.getPorts(deviceId)) {
545 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
546 portnums.add(port.number());
547 }
548 }
549 } else {
550 portnums.add(portCriterion.port());
551 }
Saurav Das4f980082015-11-05 13:39:15 -0800552
Saurav Das822c4e22015-10-23 10:51:11 -0700553 for (PortNumber pnum : portnums) {
Saurav Das4f980082015-11-05 13:39:15 -0800554 // create rest of flowrule
Saurav Das822c4e22015-10-23 10:51:11 -0700555 selector.matchInPort(pnum);
556 FlowRule rule = DefaultFlowRule.builder()
557 .forDevice(deviceId)
558 .withSelector(selector.build())
559 .withTreatment(treatment.build())
560 .withPriority(DEFAULT_PRIORITY)
561 .fromApp(applicationId)
562 .makePermanent()
563 .forTable(VLAN_TABLE).build();
Charles Chan14967c22015-12-07 11:11:50 -0800564
565 if (preSelector != null) {
566 preSelector.matchInPort(pnum);
567 FlowRule preRule = DefaultFlowRule.builder()
568 .forDevice(deviceId)
569 .withSelector(preSelector.build())
570 .withTreatment(preTreatment.build())
571 .withPriority(DEFAULT_PRIORITY)
572 .fromApp(applicationId)
573 .makePermanent()
574 .forTable(VLAN_TABLE).build();
575 rules.add(preRule);
576 }
577
Saurav Das822c4e22015-10-23 10:51:11 -0700578 rules.add(rule);
579 }
580 return rules;
581 }
582
583 /**
584 * Allows routed packets with correct destination MAC to be directed
585 * to unicast-IP routing table or MPLS forwarding table.
Saurav Das822c4e22015-10-23 10:51:11 -0700586 *
587 * @param portCriterion port on device for which this filter is programmed
588 * @param ethCriterion dstMac of device for which is filter is programmed
589 * @param vidCriterion vlan assigned to port, or NONE for untagged
Saurav Das0e99e2b2015-10-28 12:39:42 -0700590 * @param assignedVlan assigned vlan-id for untagged packets
Saurav Das822c4e22015-10-23 10:51:11 -0700591 * @param applicationId for application programming this filter
592 * @return list of FlowRule for port-vlan filters
593
594 */
595 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
596 EthCriterion ethCriterion,
597 VlanIdCriterion vidCriterion,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700598 VlanId assignedVlan,
Saurav Das822c4e22015-10-23 10:51:11 -0700599 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800600 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
601 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
602 return processEthDstOnlyFilter(ethCriterion, applicationId);
603 }
604
Charles Chan5b9df8d2016-03-28 22:21:40 -0700605 // Multicast MAC
606 if (ethCriterion.mask() != null) {
607 return processMcastEthDstFilter(ethCriterion, applicationId);
608 }
609
Saurav Das822c4e22015-10-23 10:51:11 -0700610 //handling untagged packets via assigned VLAN
611 if (vidCriterion.vlanId() == VlanId.NONE) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700612 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
Saurav Das822c4e22015-10-23 10:51:11 -0700613 }
614 // ofdpa cannot match on ALL portnumber, so we need to use separate
615 // rules for each port.
616 List<PortNumber> portnums = new ArrayList<PortNumber>();
617 if (portCriterion.port() == PortNumber.ALL) {
618 for (Port port : deviceService.getPorts(deviceId)) {
619 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
620 portnums.add(port.number());
621 }
622 }
623 } else {
624 portnums.add(portCriterion.port());
625 }
626
627 List<FlowRule> rules = new ArrayList<FlowRule>();
628 for (PortNumber pnum : portnums) {
Charles Chan14967c22015-12-07 11:11:50 -0800629 OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(vidCriterion.vlanId());
Saurav Das822c4e22015-10-23 10:51:11 -0700630 // for unicast IP packets
631 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
632 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
633 selector.matchInPort(pnum);
Charles Chan14967c22015-12-07 11:11:50 -0800634 selector.extension(ofdpaMatchVlanVid, deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -0700635 selector.matchEthType(Ethernet.TYPE_IPV4);
636 selector.matchEthDst(ethCriterion.mac());
637 treatment.transition(UNICAST_ROUTING_TABLE);
638 FlowRule rule = DefaultFlowRule.builder()
639 .forDevice(deviceId)
640 .withSelector(selector.build())
641 .withTreatment(treatment.build())
642 .withPriority(DEFAULT_PRIORITY)
643 .fromApp(applicationId)
644 .makePermanent()
645 .forTable(TMAC_TABLE).build();
646 rules.add(rule);
647 //for MPLS packets
648 selector = DefaultTrafficSelector.builder();
649 treatment = DefaultTrafficTreatment.builder();
650 selector.matchInPort(pnum);
Charles Chan14967c22015-12-07 11:11:50 -0800651 selector.extension(ofdpaMatchVlanVid, deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -0700652 selector.matchEthType(Ethernet.MPLS_UNICAST);
653 selector.matchEthDst(ethCriterion.mac());
654 treatment.transition(MPLS_TABLE_0);
655 rule = DefaultFlowRule.builder()
656 .forDevice(deviceId)
657 .withSelector(selector.build())
658 .withTreatment(treatment.build())
659 .withPriority(DEFAULT_PRIORITY)
660 .fromApp(applicationId)
661 .makePermanent()
662 .forTable(TMAC_TABLE).build();
663 rules.add(rule);
Pier Ventree0ae7a32016-11-23 09:57:42 -0800664 /*
665 * TMAC rules for IPv6 packets
666 */
667 selector = DefaultTrafficSelector.builder();
668 treatment = DefaultTrafficTreatment.builder();
669 selector.matchInPort(pnum);
670 selector.extension(ofdpaMatchVlanVid, deviceId);
671 selector.matchEthType(Ethernet.TYPE_IPV6);
672 selector.matchEthDst(ethCriterion.mac());
673 treatment.transition(UNICAST_ROUTING_TABLE);
674 rule = DefaultFlowRule.builder()
675 .forDevice(deviceId)
676 .withSelector(selector.build())
677 .withTreatment(treatment.build())
678 .withPriority(DEFAULT_PRIORITY)
679 .fromApp(applicationId)
680 .makePermanent()
681 .forTable(TMAC_TABLE).build();
682 rules.add(rule);
Saurav Das822c4e22015-10-23 10:51:11 -0700683 }
684 return rules;
685 }
686
Charles Chan5270ed02016-01-30 23:22:37 -0800687 protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
688 ApplicationId applicationId) {
Pier Luigi0e358632017-01-31 09:35:05 -0800689 ImmutableList.Builder<FlowRule> builder = ImmutableList.builder();
690
Charles Chan5270ed02016-01-30 23:22:37 -0800691 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
692 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
693 selector.matchEthType(Ethernet.TYPE_IPV4);
694 selector.matchEthDst(ethCriterion.mac());
695 treatment.transition(UNICAST_ROUTING_TABLE);
696 FlowRule rule = DefaultFlowRule.builder()
697 .forDevice(deviceId)
698 .withSelector(selector.build())
699 .withTreatment(treatment.build())
700 .withPriority(DEFAULT_PRIORITY)
701 .fromApp(applicationId)
702 .makePermanent()
703 .forTable(TMAC_TABLE).build();
Pier Luigi0e358632017-01-31 09:35:05 -0800704 builder.add(rule);
705
706 selector = DefaultTrafficSelector.builder();
707 treatment = DefaultTrafficTreatment.builder();
708 selector.matchEthType(Ethernet.TYPE_IPV6);
709 selector.matchEthDst(ethCriterion.mac());
710 treatment.transition(UNICAST_ROUTING_TABLE);
711 rule = DefaultFlowRule.builder()
712 .forDevice(deviceId)
713 .withSelector(selector.build())
714 .withTreatment(treatment.build())
715 .withPriority(DEFAULT_PRIORITY)
716 .fromApp(applicationId)
717 .makePermanent()
718 .forTable(TMAC_TABLE).build();
719 return builder.add(rule).build();
Charles Chan5270ed02016-01-30 23:22:37 -0800720 }
721
Charles Chan5b9df8d2016-03-28 22:21:40 -0700722 protected List<FlowRule> processMcastEthDstFilter(EthCriterion ethCriterion,
723 ApplicationId applicationId) {
724 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
725 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
726 selector.matchEthType(Ethernet.TYPE_IPV4);
727 selector.matchEthDstMasked(ethCriterion.mac(), ethCriterion.mask());
728 treatment.transition(MULTICAST_ROUTING_TABLE);
729 FlowRule rule = DefaultFlowRule.builder()
730 .forDevice(deviceId)
731 .withSelector(selector.build())
732 .withTreatment(treatment.build())
733 .withPriority(DEFAULT_PRIORITY)
734 .fromApp(applicationId)
735 .makePermanent()
736 .forTable(TMAC_TABLE).build();
737 return ImmutableList.<FlowRule>builder().add(rule).build();
738 }
739
Saurav Das822c4e22015-10-23 10:51:11 -0700740 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
741 switch (fwd.flag()) {
742 case SPECIFIC:
743 return processSpecific(fwd);
744 case VERSATILE:
745 return processVersatile(fwd);
746 default:
747 fail(fwd, ObjectiveError.UNKNOWN);
748 log.warn("Unknown forwarding flag {}", fwd.flag());
749 }
750 return Collections.emptySet();
751 }
752
Pier Ventree0ae7a32016-11-23 09:57:42 -0800753
754
Saurav Das822c4e22015-10-23 10:51:11 -0700755 /**
756 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
757 * ACL table.
758 * @param fwd the forwarding objective of type 'versatile'
759 * @return a collection of flow rules to be sent to the switch. An empty
760 * collection may be returned if there is a problem in processing
761 * the flow rule
762 */
Saurav Das52025962016-01-28 22:30:01 -0800763 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
Saurav Dasd2fded02016-12-02 15:43:47 -0800764 log.info("Processing versatile forwarding objective:{} in dev:{}",
765 fwd.id(), deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -0700766
767 EthTypeCriterion ethType =
Saurav Das77b5e902016-01-27 17:01:59 -0800768 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
Saurav Das822c4e22015-10-23 10:51:11 -0700769 if (ethType == null) {
Saurav Dasd2fded02016-12-02 15:43:47 -0800770 log.error("Versatile forwarding objective:{} must include ethType",
771 fwd.id());
Saurav Das822c4e22015-10-23 10:51:11 -0700772 fail(fwd, ObjectiveError.BADPARAMS);
773 return Collections.emptySet();
774 }
775 if (fwd.nextId() == null && fwd.treatment() == null) {
776 log.error("Forwarding objective {} from {} must contain "
777 + "nextId or Treatment", fwd.selector(), fwd.appId());
Zsolt Haraszti9faab752016-02-17 15:55:20 -0800778 fail(fwd, ObjectiveError.BADPARAMS);
Saurav Das822c4e22015-10-23 10:51:11 -0700779 return Collections.emptySet();
780 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800781
Saurav Das77b5e902016-01-27 17:01:59 -0800782 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
783 fwd.selector().criteria().forEach(criterion -> {
784 if (criterion instanceof VlanIdCriterion) {
785 VlanId vlanId = ((VlanIdCriterion) criterion).vlanId();
786 // ensure that match does not include vlan = NONE as OF-DPA does not
787 // match untagged packets this way in the ACL table.
788 if (vlanId.equals(VlanId.NONE)) {
789 return;
790 }
791 OfdpaMatchVlanVid ofdpaMatchVlanVid =
792 new OfdpaMatchVlanVid(vlanId);
793 sbuilder.extension(ofdpaMatchVlanVid, deviceId);
Pier Ventree0ae7a32016-11-23 09:57:42 -0800794 } else if (criterion instanceof Icmpv6TypeCriterion ||
795 criterion instanceof Icmpv6CodeCriterion) {
796 /*
797 * We silenty discard these criterions, our current
798 * OFDPA platform does not support these matches on
799 * the ACL table.
800 */
801 log.warn("ICMPv6 Type and ICMPv6 Code are not supported");
Saurav Das77b5e902016-01-27 17:01:59 -0800802 } else {
803 sbuilder.add(criterion);
804 }
805 });
806
Saurav Das822c4e22015-10-23 10:51:11 -0700807 // XXX driver does not currently do type checking as per Tables 65-67 in
808 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
Saurav Das49cb5a12016-01-16 22:54:07 -0800809 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
810 if (fwd.treatment() != null) {
811 for (Instruction ins : fwd.treatment().allInstructions()) {
812 if (ins instanceof OutputInstruction) {
813 OutputInstruction o = (OutputInstruction) ins;
814 if (o.port() == PortNumber.CONTROLLER) {
815 ttBuilder.add(o);
816 } else {
817 log.warn("Only allowed treatments in versatile forwarding "
818 + "objectives are punts to the controller");
819 }
820 } else {
821 log.warn("Cannot process instruction in versatile fwd {}", ins);
822 }
Saurav Das822c4e22015-10-23 10:51:11 -0700823 }
Charles Chan2df0e8a2017-01-09 11:45:08 -0800824 if (fwd.treatment().clearedDeferred()) {
825 ttBuilder.wipeDeferred();
826 }
Saurav Das822c4e22015-10-23 10:51:11 -0700827 }
Saurav Das822c4e22015-10-23 10:51:11 -0700828 if (fwd.nextId() != null) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800829 // overide case
830 NextGroup next = getGroupForNextObjective(fwd.nextId());
831 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
832 // we only need the top level group's key to point the flow to it
833 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
834 if (group == null) {
835 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
836 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
837 fail(fwd, ObjectiveError.GROUPMISSING);
838 return Collections.emptySet();
839 }
840 ttBuilder.deferred().group(group.id());
Saurav Das822c4e22015-10-23 10:51:11 -0700841 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800842
843 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
844 .fromApp(fwd.appId())
845 .withPriority(fwd.priority())
846 .forDevice(deviceId)
Saurav Das77b5e902016-01-27 17:01:59 -0800847 .withSelector(sbuilder.build())
Saurav Das49cb5a12016-01-16 22:54:07 -0800848 .withTreatment(ttBuilder.build())
849 .makePermanent()
850 .forTable(ACL_TABLE);
851 return Collections.singletonList(ruleBuilder.build());
Saurav Das822c4e22015-10-23 10:51:11 -0700852 }
853
854 /**
855 * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table
Saurav Das8a0732e2015-11-20 15:27:53 -0800856 * (unicast or multicast) or the L2 table (mac + vlan) or the MPLS table.
Saurav Das822c4e22015-10-23 10:51:11 -0700857 *
858 * @param fwd the forwarding objective of type 'specific'
859 * @return a collection of flow rules. Typically there will be only one
860 * for this type of forwarding objective. An empty set may be
861 * returned if there is an issue in processing the objective.
862 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800863 protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
Saurav Das25190812016-05-27 13:54:07 -0700864 log.debug("Processing specific fwd objective:{} in dev:{} with next:{}",
Saurav Das4ce45962015-11-24 23:21:05 -0800865 fwd.id(), deviceId, fwd.nextId());
866 boolean isEthTypeObj = isSupportedEthTypeObjective(fwd);
867 boolean isEthDstObj = isSupportedEthDstObjective(fwd);
868
869 if (isEthTypeObj) {
870 return processEthTypeSpecific(fwd);
871 } else if (isEthDstObj) {
872 return processEthDstSpecific(fwd);
873 } else {
874 log.warn("processSpecific: Unsupported forwarding objective "
875 + "criteria fwd:{} in dev:{}", fwd.nextId(), deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -0700876 fail(fwd, ObjectiveError.UNSUPPORTED);
877 return Collections.emptySet();
878 }
Saurav Das4ce45962015-11-24 23:21:05 -0800879 }
880
Saurav Das4ce45962015-11-24 23:21:05 -0800881 /**
882 * Handles forwarding rules to the IP and MPLS tables.
883 *
884 * @param fwd the forwarding objective
885 * @return A collection of flow rules, or an empty set
886 */
887 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Charles Chancad338a2016-09-16 18:03:11 -0700888 return processEthTypeSpecificInternal(fwd, false, ACL_TABLE);
Charles Chanf9e98652016-09-07 16:54:23 -0700889 }
890
891 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800892 * Helper method to build Ipv6 selector using the selector provided by
893 * a forwarding objective.
894 *
895 * @param builderToUpdate the builder to update
896 * @param fwd the selector to read
897 * @return 0 if the update ends correctly. -1 if the matches
898 * are not yet supported
899 */
900 protected int buildIpv6Selector(TrafficSelector.Builder builderToUpdate,
901 ForwardingObjective fwd) {
902
903 TrafficSelector selector = fwd.selector();
904
905 IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
906 if (ipv6Dst.isMulticast()) {
907 log.warn("IPv6 Multicast is currently not supported");
908 fail(fwd, ObjectiveError.BADPARAMS);
909 return -1;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800910 }
Pier Luigi69fd4312017-01-28 17:58:58 -0800911 if (ipv6Dst.prefixLength() != 0) {
912 builderToUpdate.matchIPv6Dst(ipv6Dst);
913 }
914 builderToUpdate.matchEthType(Ethernet.TYPE_IPV6);
915 log.debug("processing IPv6 unicast specific forwarding objective {} -> next:{}"
916 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Pier Ventree0ae7a32016-11-23 09:57:42 -0800917 return 0;
918 }
919
920 /**
Charles Chanf9e98652016-09-07 16:54:23 -0700921 * Internal implementation of processEthTypeSpecific.
922 * <p>
923 * Wildcarded IPv4_DST is not supported in OFDPA i12. Therefore, we break
924 * the rule into 0.0.0.0/1 and 128.0.0.0/1.
925 * The allowDefaultRoute must be set to false for OFDPA i12.
926 * </p>
927 *
928 * @param fwd the forwarding objective
929 * @param allowDefaultRoute allow wildcarded IPv4_DST or not
Ray Milkey0bb1e102016-11-10 14:51:27 -0800930 * @param mplsNextTable next MPLS table
Charles Chanf9e98652016-09-07 16:54:23 -0700931 * @return A collection of flow rules, or an empty set
932 */
933 protected Collection<FlowRule> processEthTypeSpecificInternal(ForwardingObjective fwd,
Charles Chancad338a2016-09-16 18:03:11 -0700934 boolean allowDefaultRoute,
935 int mplsNextTable) {
Saurav Das4ce45962015-11-24 23:21:05 -0800936 TrafficSelector selector = fwd.selector();
937 EthTypeCriterion ethType =
938 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Flavio Castroe10fa242016-01-15 12:43:51 -0800939 boolean defaultRule = false;
940 boolean popMpls = false;
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700941 boolean emptyGroup = false;
Charles Chan188ebf52015-12-23 00:15:11 -0800942 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800943 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Charles Chan14967c22015-12-07 11:11:50 -0800944 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800945 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
Charles Chan14967c22015-12-07 11:11:50 -0800946
Saurav Das8a0732e2015-11-20 15:27:53 -0800947 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800948 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700949 if (ipv4Dst.isMulticast()) {
950 if (ipv4Dst.prefixLength() != 32) {
951 log.warn("Multicast specific forwarding objective can only be /32");
952 fail(fwd, ObjectiveError.BADPARAMS);
953 return ImmutableSet.of();
954 }
955 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
956 if (assignedVlan == null) {
957 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
958 fail(fwd, ObjectiveError.BADPARAMS);
959 return ImmutableSet.of();
960 }
961 OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(assignedVlan);
962 filteredSelector.extension(ofdpaMatchVlanVid, deviceId);
963 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
964 forTableId = MULTICAST_ROUTING_TABLE;
965 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
966 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800967 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700968 if (ipv4Dst.prefixLength() == 0) {
969 if (allowDefaultRoute) {
970 // The entire IPV4_DST field is wildcarded intentionally
971 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
972 } else {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800973 // NOTE: The switch does not support matching 0.0.0.0/0
974 // Split it into 0.0.0.0/1 and 128.0.0.0/1
Charles Chanf9e98652016-09-07 16:54:23 -0700975 filteredSelector.matchEthType(Ethernet.TYPE_IPV4)
976 .matchIPDst(IpPrefix.valueOf("0.0.0.0/1"));
977 complementarySelector.matchEthType(Ethernet.TYPE_IPV4)
978 .matchIPDst(IpPrefix.valueOf("128.0.0.0/1"));
979 defaultRule = true;
980 }
Charles Chan5b9df8d2016-03-28 22:21:40 -0700981 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700982 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700983 }
984 forTableId = UNICAST_ROUTING_TABLE;
985 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
986 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800987 }
Charles Chan14967c22015-12-07 11:11:50 -0800988
989 if (fwd.treatment() != null) {
990 for (Instruction instr : fwd.treatment().allInstructions()) {
991 if (instr instanceof L3ModificationInstruction &&
992 ((L3ModificationInstruction) instr).subtype() == L3SubType.DEC_TTL) {
Saurav Das9c705342017-01-06 11:36:01 -0800993 // XXX decrementing IP ttl is done automatically for routing, this
994 // action is ignored or rejected in ofdpa as it is not fully implemented
995 //tb.deferred().add(instr);
Charles Chan14967c22015-12-07 11:11:50 -0800996 }
997 }
998 }
999
Pier Ventree0ae7a32016-11-23 09:57:42 -08001000 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
1001 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
1002 return Collections.emptyList();
1003 }
1004 forTableId = UNICAST_ROUTING_TABLE;
1005 if (fwd.treatment() != null) {
1006 for (Instruction instr : fwd.treatment().allInstructions()) {
1007 if (instr instanceof L3ModificationInstruction &&
1008 ((L3ModificationInstruction) instr).subtype() == L3SubType.DEC_TTL) {
1009 // XXX decrementing IP ttl is done automatically for routing, this
1010 // action is ignored or rejected in ofdpa as it is not fully implemented
1011 //tb.deferred().add(instr);
1012 }
1013 }
1014 }
Saurav Das8a0732e2015-11-20 15:27:53 -08001015 } else {
1016 filteredSelector
1017 .matchEthType(Ethernet.MPLS_UNICAST)
1018 .matchMplsLabel(((MplsCriterion)
1019 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
1020 MplsBosCriterion bos = (MplsBosCriterion) selector
1021 .getCriterion(Criterion.Type.MPLS_BOS);
1022 if (bos != null) {
1023 filteredSelector.matchMplsBos(bos.mplsBos());
1024 }
1025 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -08001026 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
1027 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -07001028
Charles Chan14967c22015-12-07 11:11:50 -08001029 if (fwd.treatment() != null) {
1030 for (Instruction instr : fwd.treatment().allInstructions()) {
1031 if (instr instanceof L2ModificationInstruction &&
1032 ((L2ModificationInstruction) instr).subtype() == L2SubType.MPLS_POP) {
Saurav Das8a0732e2015-11-20 15:27:53 -08001033 popMpls = true;
Saurav Das9c705342017-01-06 11:36:01 -08001034 // OF-DPA does not pop in MPLS table. Instead it requires
1035 // setting the MPLS_TYPE so pop can happen down the pipeline
Charles Chan14967c22015-12-07 11:11:50 -08001036 }
1037 if (instr instanceof L3ModificationInstruction &&
1038 ((L3ModificationInstruction) instr).subtype() == L3SubType.DEC_TTL) {
1039 // FIXME Should modify the app to send the correct DEC_MPLS_TTL instruction
1040 tb.immediate().decMplsTtl();
1041 }
1042 if (instr instanceof L3ModificationInstruction &&
1043 ((L3ModificationInstruction) instr).subtype() == L3SubType.TTL_IN) {
1044 tb.immediate().add(instr);
1045 }
Saurav Das8a0732e2015-11-20 15:27:53 -08001046 }
1047 }
1048 }
Saurav Das822c4e22015-10-23 10:51:11 -07001049
1050 if (fwd.nextId() != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -08001051 if (forTableId == MPLS_TABLE_1 && !popMpls) {
1052 log.warn("SR CONTINUE case cannot be handled as MPLS ECMP "
Saurav Das25190812016-05-27 13:54:07 -07001053 + "is not implemented in OF-DPA yet. Aborting this flow {} -> next:{}"
1054 + "in this device {}", fwd.id(), fwd.nextId(), deviceId);
Pier Ventree0ae7a32016-11-23 09:57:42 -08001055 // XXX We could convert to forwarding to a single-port, via a MPLS interface,
1056 // or a MPLS SWAP (with-same) but that would have to be handled in the next-objective.
1057 // Also the pop-mpls logic used here won't work in non-BoS case.
Saurav Das4ce45962015-11-24 23:21:05 -08001058 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
Saurav Das8a0732e2015-11-20 15:27:53 -08001059 return Collections.emptySet();
1060 }
1061
Saurav Das423fe2b2015-12-04 10:52:59 -08001062 NextGroup next = getGroupForNextObjective(fwd.nextId());
1063 if (next != null) {
1064 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
1065 // we only need the top level group's key to point the flow to it
1066 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
1067 if (group == null) {
1068 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
1069 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
1070 fail(fwd, ObjectiveError.GROUPMISSING);
1071 return Collections.emptySet();
1072 }
1073 tb.deferred().group(group.id());
Saurav Das1ce0a7b2016-10-21 14:06:29 -07001074 // check if group is empty
1075 if (gkeys.size() == 1 && gkeys.get(0).size() == 1) {
1076 log.warn("Found empty group 0x{} in dev:{} .. will retry fwd:{}",
1077 Integer.toHexString(group.id().id()), deviceId, fwd.id());
1078 emptyGroup = true;
1079 }
Saurav Das25190812016-05-27 13:54:07 -07001080 } else {
1081 log.warn("Cannot find group for nextId:{} in dev:{}. Aborting fwd:{}",
1082 fwd.nextId(), deviceId, fwd.id());
1083 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
1084 return Collections.emptySet();
Saurav Das822c4e22015-10-23 10:51:11 -07001085 }
Saurav Das822c4e22015-10-23 10:51:11 -07001086 }
Charles Chancad338a2016-09-16 18:03:11 -07001087
1088 if (forTableId == MPLS_TABLE_1) {
1089 if (mplsNextTable == MPLS_L3_TYPE) {
1090 Ofdpa3SetMplsType setMplsType = new Ofdpa3SetMplsType(Ofdpa3MplsType.L3_PHP);
Saurav Das9c705342017-01-06 11:36:01 -08001091 // set mpls type as apply_action
1092 tb.immediate().extension(setMplsType, deviceId);
Charles Chancad338a2016-09-16 18:03:11 -07001093 }
1094 tb.transition(mplsNextTable);
1095 } else {
1096 tb.transition(ACL_TABLE);
1097 }
1098
Saurav Das822c4e22015-10-23 10:51:11 -07001099 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
1100 .fromApp(fwd.appId())
1101 .withPriority(fwd.priority())
1102 .forDevice(deviceId)
Saurav Das8a0732e2015-11-20 15:27:53 -08001103 .withSelector(filteredSelector.build())
1104 .withTreatment(tb.build())
1105 .forTable(forTableId);
Saurav Das822c4e22015-10-23 10:51:11 -07001106
1107 if (fwd.permanent()) {
1108 ruleBuilder.makePermanent();
1109 } else {
1110 ruleBuilder.makeTemporary(fwd.timeout());
1111 }
Flavio Castroe10fa242016-01-15 12:43:51 -08001112 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
1113 flowRuleCollection.add(ruleBuilder.build());
1114 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -08001115 flowRuleCollection.add(
1116 defaultRoute(fwd, complementarySelector, forTableId, tb)
1117 );
Flavio Castroe10fa242016-01-15 12:43:51 -08001118 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
1119 }
Saurav Das1ce0a7b2016-10-21 14:06:29 -07001120 // XXX retrying flows may be necessary due to bug CORD-554
1121 if (emptyGroup) {
1122 executorService.schedule(new RetryFlows(fwd, flowRuleCollection),
1123 RETRY_MS, TimeUnit.MILLISECONDS);
1124 }
Flavio Castroe10fa242016-01-15 12:43:51 -08001125 return flowRuleCollection;
Saurav Das822c4e22015-10-23 10:51:11 -07001126 }
1127
Pier Ventree0ae7a32016-11-23 09:57:42 -08001128 protected FlowRule defaultRoute(ForwardingObjective fwd,
1129 TrafficSelector.Builder complementarySelector,
1130 int forTableId,
1131 TrafficTreatment.Builder tb) {
1132 FlowRule.Builder rule = DefaultFlowRule.builder()
1133 .fromApp(fwd.appId())
1134 .withPriority(fwd.priority())
1135 .forDevice(deviceId)
1136 .withSelector(complementarySelector.build())
1137 .withTreatment(tb.build())
1138 .forTable(forTableId);
1139 if (fwd.permanent()) {
1140 rule.makePermanent();
1141 } else {
1142 rule.makeTemporary(fwd.timeout());
1143 }
1144 return rule.build();
1145 }
1146
Saurav Das4ce45962015-11-24 23:21:05 -08001147 /**
1148 * Handles forwarding rules to the L2 bridging table. Flow actions are not
1149 * allowed in the bridging table - instead we use L2 Interface group or
1150 * L2 flood group
1151 *
1152 * @param fwd the forwarding objective
1153 * @return A collection of flow rules, or an empty set
1154 */
1155 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
1156 List<FlowRule> rules = new ArrayList<>();
1157
1158 // Build filtered selector
1159 TrafficSelector selector = fwd.selector();
1160 EthCriterion ethCriterion = (EthCriterion) selector
1161 .getCriterion(Criterion.Type.ETH_DST);
1162 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
1163 .getCriterion(Criterion.Type.VLAN_VID);
1164
1165 if (vlanIdCriterion == null) {
1166 log.warn("Forwarding objective for bridging requires vlan. Not "
1167 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
1168 fail(fwd, ObjectiveError.BADPARAMS);
1169 return Collections.emptySet();
1170 }
1171
1172 TrafficSelector.Builder filteredSelectorBuilder =
1173 DefaultTrafficSelector.builder();
Yi Tseng3a77b4f2017-02-06 15:02:17 -08001174
1175 if (!ethCriterion.mac().equals(NONE) &&
1176 !ethCriterion.mac().equals(BROADCAST)) {
Saurav Das4ce45962015-11-24 23:21:05 -08001177 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
1178 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
1179 fwd.id(), fwd.nextId(), deviceId);
1180 } else {
Yi Tseng3a77b4f2017-02-06 15:02:17 -08001181 // Use wildcard DST_MAC if the MacAddress is None or Broadcast
Saurav Das4ce45962015-11-24 23:21:05 -08001182 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
1183 + "in dev:{} for vlan:{}",
1184 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
1185 }
Charles Chan14967c22015-12-07 11:11:50 -08001186 OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(vlanIdCriterion.vlanId());
1187 filteredSelectorBuilder.extension(ofdpaMatchVlanVid, deviceId);
Saurav Das4ce45962015-11-24 23:21:05 -08001188 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
1189
1190 if (fwd.treatment() != null) {
1191 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
1192 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
1193 }
1194
1195 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1196 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -08001197 NextGroup next = getGroupForNextObjective(fwd.nextId());
Saurav Das4ce45962015-11-24 23:21:05 -08001198 if (next != null) {
1199 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
1200 // we only need the top level group's key to point the flow to it
1201 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
1202 if (group != null) {
1203 treatmentBuilder.deferred().group(group.id());
1204 } else {
1205 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
1206 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
1207 fail(fwd, ObjectiveError.GROUPMISSING);
1208 return Collections.emptySet();
1209 }
1210 }
1211 }
1212 treatmentBuilder.immediate().transition(ACL_TABLE);
1213 TrafficTreatment filteredTreatment = treatmentBuilder.build();
1214
1215 // Build bridging table entries
1216 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
1217 flowRuleBuilder.fromApp(fwd.appId())
1218 .withPriority(fwd.priority())
1219 .forDevice(deviceId)
1220 .withSelector(filteredSelector)
1221 .withTreatment(filteredTreatment)
1222 .forTable(BRIDGING_TABLE);
1223 if (fwd.permanent()) {
1224 flowRuleBuilder.makePermanent();
1225 } else {
1226 flowRuleBuilder.makeTemporary(fwd.timeout());
1227 }
1228 rules.add(flowRuleBuilder.build());
1229 return rules;
1230 }
1231
Saurav Das1ce0a7b2016-10-21 14:06:29 -07001232 //////////////////////////////////////
1233 // Helper Methods and Classes
1234 //////////////////////////////////////
1235
1236 private boolean isSupportedEthTypeObjective(ForwardingObjective fwd) {
1237 TrafficSelector selector = fwd.selector();
1238 EthTypeCriterion ethType = (EthTypeCriterion) selector
1239 .getCriterion(Criterion.Type.ETH_TYPE);
1240 return !((ethType == null) ||
1241 ((ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -08001242 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) &&
1243 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6));
Saurav Das1ce0a7b2016-10-21 14:06:29 -07001244 }
1245
1246 private boolean isSupportedEthDstObjective(ForwardingObjective fwd) {
1247 TrafficSelector selector = fwd.selector();
1248 EthCriterion ethDst = (EthCriterion) selector
1249 .getCriterion(Criterion.Type.ETH_DST);
1250 VlanIdCriterion vlanId = (VlanIdCriterion) selector
1251 .getCriterion(Criterion.Type.VLAN_VID);
1252 return !(ethDst == null && vlanId == null);
1253 }
1254
Saurav Das423fe2b2015-12-04 10:52:59 -08001255 protected NextGroup getGroupForNextObjective(Integer nextId) {
1256 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
1257 if (next != null) {
1258 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
1259 if (gkeys != null && !gkeys.isEmpty()) {
1260 return next;
1261 } else {
1262 log.warn("Empty next group found in FlowObjective store for "
1263 + "next-id:{} in dev:{}", nextId, deviceId);
1264 }
1265 } else {
1266 log.warn("next-id {} not found in Flow objective store for dev:{}",
1267 nextId, deviceId);
1268 }
1269 return null;
1270 }
1271
Charles Chan188ebf52015-12-23 00:15:11 -08001272 protected static void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001273 obj.context().ifPresent(context -> context.onSuccess(obj));
Saurav Das822c4e22015-10-23 10:51:11 -07001274 }
1275
Charles Chan188ebf52015-12-23 00:15:11 -08001276 protected static void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001277 obj.context().ifPresent(context -> context.onError(obj, error));
Saurav Das822c4e22015-10-23 10:51:11 -07001278 }
Saurav Das24431192016-03-07 19:13:00 -08001279
Saurav Das24431192016-03-07 19:13:00 -08001280 @Override
1281 public List<String> getNextMappings(NextGroup nextGroup) {
1282 List<String> mappings = new ArrayList<>();
1283 List<Deque<GroupKey>> gkeys = appKryo.deserialize(nextGroup.data());
1284 for (Deque<GroupKey> gkd : gkeys) {
1285 Group lastGroup = null;
Saurav Das8be4e3a2016-03-11 17:19:07 -08001286 StringBuffer gchain = new StringBuffer();
Saurav Das24431192016-03-07 19:13:00 -08001287 for (GroupKey gk : gkd) {
1288 Group g = groupService.getGroup(deviceId, gk);
Saurav Das8be4e3a2016-03-11 17:19:07 -08001289 if (g == null) {
Saurav Das25190812016-05-27 13:54:07 -07001290 gchain.append(" NoGrp").append(" -->");
Saurav Das8be4e3a2016-03-11 17:19:07 -08001291 continue;
1292 }
1293 gchain.append(" 0x").append(Integer.toHexString(g.id().id()))
1294 .append(" -->");
Saurav Das24431192016-03-07 19:13:00 -08001295 lastGroup = g;
1296 }
1297 // add port information for last group in group-chain
Saurav Das25190812016-05-27 13:54:07 -07001298 List<Instruction> lastGroupIns = new ArrayList<Instruction>();
Saurav Das1ce0a7b2016-10-21 14:06:29 -07001299 if (lastGroup != null && !lastGroup.buckets().buckets().isEmpty()) {
Saurav Das25190812016-05-27 13:54:07 -07001300 lastGroupIns = lastGroup.buckets().buckets().get(0)
1301 .treatment().allInstructions();
1302 }
1303 for (Instruction i: lastGroupIns) {
Saurav Das24431192016-03-07 19:13:00 -08001304 if (i instanceof OutputInstruction) {
Saurav Das8be4e3a2016-03-11 17:19:07 -08001305 gchain.append(" port:").append(((OutputInstruction) i).port());
Saurav Das24431192016-03-07 19:13:00 -08001306 }
1307 }
Saurav Das8be4e3a2016-03-11 17:19:07 -08001308 mappings.add(gchain.toString());
Saurav Das24431192016-03-07 19:13:00 -08001309 }
1310 return mappings;
1311 }
Charles Chan5b9df8d2016-03-28 22:21:40 -07001312
1313 protected static VlanId readVlanFromSelector(TrafficSelector selector) {
Saurav Das59232cf2016-04-27 18:35:50 -07001314 if (selector == null) {
1315 return null;
1316 }
Charles Chan5b9df8d2016-03-28 22:21:40 -07001317 Criterion criterion = selector.getCriterion(Criterion.Type.VLAN_VID);
1318 return (criterion == null)
1319 ? null : ((VlanIdCriterion) criterion).vlanId();
1320 }
1321
1322 protected static IpPrefix readIpDstFromSelector(TrafficSelector selector) {
Saurav Das59232cf2016-04-27 18:35:50 -07001323 if (selector == null) {
1324 return null;
1325 }
Charles Chan5b9df8d2016-03-28 22:21:40 -07001326 Criterion criterion = selector.getCriterion(Criterion.Type.IPV4_DST);
1327 return (criterion == null) ? null : ((IPCriterion) criterion).ip();
1328 }
Charles Chand55e84d2016-03-30 17:54:24 -07001329
1330 private static VlanId readVlanFromTreatment(TrafficTreatment treatment) {
Saurav Das59232cf2016-04-27 18:35:50 -07001331 if (treatment == null) {
1332 return null;
1333 }
Charles Chand55e84d2016-03-30 17:54:24 -07001334 for (Instruction i : treatment.allInstructions()) {
1335 if (i instanceof ModVlanIdInstruction) {
1336 return ((ModVlanIdInstruction) i).vlanId();
1337 }
1338 }
1339 return null;
1340 }
Saurav Das1ce0a7b2016-10-21 14:06:29 -07001341
1342 /**
1343 * Utility class that retries sending flows a fixed number of times, even if
1344 * some of the attempts are successful. Used only for forwarding objectives.
1345 */
1346 protected final class RetryFlows implements Runnable {
1347 int attempts = MAX_RETRY_ATTEMPTS;
1348 private Collection<FlowRule> retryFlows;
1349 private ForwardingObjective fwd;
1350
1351 RetryFlows(ForwardingObjective fwd, Collection<FlowRule> retryFlows) {
1352 this.fwd = fwd;
1353 this.retryFlows = retryFlows;
1354 }
1355
1356 @Override
1357 public void run() {
1358 log.info("RETRY FLOWS ATTEMPT# {} for fwd:{} rules:{}",
1359 MAX_RETRY_ATTEMPTS - attempts, fwd.id(), retryFlows.size());
1360 sendForward(fwd, retryFlows);
1361 if (--attempts > 0) {
1362 executorService.schedule(this, RETRY_MS, TimeUnit.MILLISECONDS);
1363 }
1364 }
1365 }
1366
Saurav Das822c4e22015-10-23 10:51:11 -07001367}