blob: 97751ecb4fa0eb98ec75a2382add518c2ceeaf4c [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
Saurav Das822c4e22015-10-23 10:51:11 -070018import static org.slf4j.LoggerFactory.getLogger;
19
Saurav Das8a0732e2015-11-20 15:27:53 -080020import java.util.ArrayDeque;
Saurav Das822c4e22015-10-23 10:51:11 -070021import java.util.ArrayList;
22import java.util.Collection;
23import java.util.Collections;
Saurav Das8a0732e2015-11-20 15:27:53 -080024import java.util.Deque;
Saurav Das822c4e22015-10-23 10:51:11 -070025import java.util.List;
Sho SHIMIZU45906042016-01-13 23:05:54 -080026import java.util.Objects;
Saurav Das822c4e22015-10-23 10:51:11 -070027import java.util.Set;
28import java.util.concurrent.ConcurrentHashMap;
Saurav Das822c4e22015-10-23 10:51:11 -070029
Charles Chan5270ed02016-01-30 23:22:37 -080030import com.google.common.collect.ImmutableList;
Charles Chan5b9df8d2016-03-28 22:21:40 -070031import com.google.common.collect.ImmutableSet;
Saurav Das822c4e22015-10-23 10:51:11 -070032import org.onlab.osgi.ServiceDirectory;
Saurav Das822c4e22015-10-23 10:51:11 -070033import org.onlab.packet.Ethernet;
Charles Chan14967c22015-12-07 11:11:50 -080034import org.onlab.packet.IpPrefix;
Saurav Das822c4e22015-10-23 10:51:11 -070035import org.onlab.packet.MacAddress;
Saurav Das822c4e22015-10-23 10:51:11 -070036import org.onlab.packet.VlanId;
37import org.onlab.util.KryoNamespace;
38import org.onosproject.core.ApplicationId;
39import org.onosproject.core.CoreService;
Charles Chan14967c22015-12-07 11:11:50 -080040import org.onosproject.driver.extensions.OfdpaMatchVlanVid;
41import org.onosproject.driver.extensions.OfdpaSetVlanVid;
Saurav Das822c4e22015-10-23 10:51:11 -070042import org.onosproject.net.DeviceId;
43import org.onosproject.net.Port;
44import org.onosproject.net.PortNumber;
45import org.onosproject.net.behaviour.NextGroup;
46import org.onosproject.net.behaviour.Pipeliner;
47import org.onosproject.net.behaviour.PipelinerContext;
48import org.onosproject.net.device.DeviceService;
49import org.onosproject.net.driver.AbstractHandlerBehaviour;
50import org.onosproject.net.flow.DefaultFlowRule;
51import org.onosproject.net.flow.DefaultTrafficSelector;
52import org.onosproject.net.flow.DefaultTrafficTreatment;
53import org.onosproject.net.flow.FlowRule;
54import org.onosproject.net.flow.FlowRuleOperations;
55import org.onosproject.net.flow.FlowRuleOperationsContext;
56import org.onosproject.net.flow.FlowRuleService;
57import org.onosproject.net.flow.TrafficSelector;
58import org.onosproject.net.flow.TrafficTreatment;
59import org.onosproject.net.flow.criteria.Criteria;
60import org.onosproject.net.flow.criteria.Criterion;
61import org.onosproject.net.flow.criteria.EthCriterion;
62import org.onosproject.net.flow.criteria.EthTypeCriterion;
Charles Chan14967c22015-12-07 11:11:50 -080063import org.onosproject.net.flow.criteria.ExtensionCriterion;
Saurav Das822c4e22015-10-23 10:51:11 -070064import org.onosproject.net.flow.criteria.IPCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080065import org.onosproject.net.flow.criteria.MplsBosCriterion;
66import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das822c4e22015-10-23 10:51:11 -070067import org.onosproject.net.flow.criteria.PortCriterion;
68import org.onosproject.net.flow.criteria.VlanIdCriterion;
69import org.onosproject.net.flow.instructions.Instruction;
70import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
71import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Saurav Das8a0732e2015-11-20 15:27:53 -080072import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
Saurav Das822c4e22015-10-23 10:51:11 -070073import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
Charles Chan14967c22015-12-07 11:11:50 -080074import org.onosproject.net.flow.instructions.L3ModificationInstruction;
75import org.onosproject.net.flow.instructions.L3ModificationInstruction.L3SubType;
Saurav Das822c4e22015-10-23 10:51:11 -070076import org.onosproject.net.flowobjective.FilteringObjective;
77import org.onosproject.net.flowobjective.FlowObjectiveStore;
78import org.onosproject.net.flowobjective.ForwardingObjective;
79import org.onosproject.net.flowobjective.NextObjective;
80import org.onosproject.net.flowobjective.Objective;
81import org.onosproject.net.flowobjective.ObjectiveError;
Saurav Das822c4e22015-10-23 10:51:11 -070082import org.onosproject.net.group.DefaultGroupKey;
83import org.onosproject.net.group.Group;
Saurav Das822c4e22015-10-23 10:51:11 -070084import org.onosproject.net.group.GroupKey;
Saurav Das822c4e22015-10-23 10:51:11 -070085import org.onosproject.net.group.GroupService;
Saurav Das822c4e22015-10-23 10:51:11 -070086import org.onosproject.store.serializers.KryoNamespaces;
87import org.slf4j.Logger;
88
Saurav Das822c4e22015-10-23 10:51:11 -070089/**
90 * Driver for Broadcom's OF-DPA v2.0 TTP.
91 *
92 */
Charles Chan361154b2016-03-24 10:23:39 -070093public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeliner {
Saurav Das822c4e22015-10-23 10:51:11 -070094 protected static final int PORT_TABLE = 0;
95 protected static final int VLAN_TABLE = 10;
96 protected static final int TMAC_TABLE = 20;
97 protected static final int UNICAST_ROUTING_TABLE = 30;
98 protected static final int MULTICAST_ROUTING_TABLE = 40;
99 protected static final int MPLS_TABLE_0 = 23;
100 protected static final int MPLS_TABLE_1 = 24;
101 protected static final int BRIDGING_TABLE = 50;
102 protected static final int ACL_TABLE = 60;
103 protected static final int MAC_LEARNING_TABLE = 254;
104 protected static final long OFPP_MAX = 0xffffff00L;
105
Saurav Das52025962016-01-28 22:30:01 -0800106 protected static final int HIGHEST_PRIORITY = 0xffff;
Saurav Das2857f382015-11-03 14:39:27 -0800107 protected static final int DEFAULT_PRIORITY = 0x8000;
Saurav Das822c4e22015-10-23 10:51:11 -0700108 protected static final int LOWEST_PRIORITY = 0x0;
109
Saurav Das822c4e22015-10-23 10:51:11 -0700110 private final Logger log = getLogger(getClass());
Charles Chan425854b2016-04-11 15:32:12 -0700111 protected ServiceDirectory serviceDirectory;
Saurav Das822c4e22015-10-23 10:51:11 -0700112 protected FlowRuleService flowRuleService;
Charles Chan425854b2016-04-11 15:32:12 -0700113 protected CoreService coreService;
Saurav Das8a0732e2015-11-20 15:27:53 -0800114 protected GroupService groupService;
115 protected FlowObjectiveStore flowObjectiveStore;
Saurav Das822c4e22015-10-23 10:51:11 -0700116 protected DeviceId deviceId;
117 protected ApplicationId driverId;
Saurav Das822c4e22015-10-23 10:51:11 -0700118 protected DeviceService deviceService;
Charles Chan188ebf52015-12-23 00:15:11 -0800119 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
Saurav Das822c4e22015-10-23 10:51:11 -0700120 .register(KryoNamespaces.API)
121 .register(GroupKey.class)
122 .register(DefaultGroupKey.class)
Charles Chan361154b2016-03-24 10:23:39 -0700123 .register(Ofdpa2GroupHandler.OfdpaNextGroup.class)
Saurav Das822c4e22015-10-23 10:51:11 -0700124 .register(byte[].class)
Saurav Das8a0732e2015-11-20 15:27:53 -0800125 .register(ArrayDeque.class)
Saurav Das822c4e22015-10-23 10:51:11 -0700126 .build();
127
Charles Chan425854b2016-04-11 15:32:12 -0700128 protected Ofdpa2GroupHandler groupHandler;
Saurav Das822c4e22015-10-23 10:51:11 -0700129
Saurav Das52025962016-01-28 22:30:01 -0800130 protected Set<IPCriterion> sentIpFilters = Collections.newSetFromMap(
Charles Chan188ebf52015-12-23 00:15:11 -0800131 new ConcurrentHashMap<>());
Saurav Das4f980082015-11-05 13:39:15 -0800132
Saurav Das822c4e22015-10-23 10:51:11 -0700133 @Override
134 public void init(DeviceId deviceId, PipelinerContext context) {
Saurav Das822c4e22015-10-23 10:51:11 -0700135 this.deviceId = deviceId;
136
Charles Chan188ebf52015-12-23 00:15:11 -0800137 // Initialize OFDPA group handler
Charles Chan425854b2016-04-11 15:32:12 -0700138 groupHandler = new Ofdpa2GroupHandler();
139 groupHandler.init(deviceId, context);
Saurav Das822c4e22015-10-23 10:51:11 -0700140
Charles Chan425854b2016-04-11 15:32:12 -0700141 serviceDirectory = context.directory();
Saurav Das822c4e22015-10-23 10:51:11 -0700142 coreService = serviceDirectory.get(CoreService.class);
143 flowRuleService = serviceDirectory.get(FlowRuleService.class);
144 groupService = serviceDirectory.get(GroupService.class);
145 flowObjectiveStore = context.store();
Saurav Das822c4e22015-10-23 10:51:11 -0700146 deviceService = serviceDirectory.get(DeviceService.class);
Saurav Das822c4e22015-10-23 10:51:11 -0700147
148 driverId = coreService.registerApplication(
Charles Chan425854b2016-04-11 15:32:12 -0700149 "org.onosproject.driver.Ofdpa2Pipeline");
Saurav Das822c4e22015-10-23 10:51:11 -0700150
Saurav Das822c4e22015-10-23 10:51:11 -0700151 initializePipeline();
Saurav Das822c4e22015-10-23 10:51:11 -0700152 }
153
154 protected void initializePipeline() {
Charles Chan188ebf52015-12-23 00:15:11 -0800155 // OF-DPA does not require initializing the pipeline as it puts default
156 // rules automatically in the hardware. However emulation of OFDPA in
157 // software switches does require table-miss-entries.
Saurav Das822c4e22015-10-23 10:51:11 -0700158 }
159
160 //////////////////////////////////////
161 // Flow Objectives
162 //////////////////////////////////////
163
164 @Override
165 public void filter(FilteringObjective filteringObjective) {
166 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
167 processFilter(filteringObjective,
168 filteringObjective.op() == Objective.Operation.ADD,
169 filteringObjective.appId());
170 } else {
171 // Note that packets that don't match the PERMIT filter are
172 // automatically denied. The DENY filter is used to deny packets
173 // that are otherwise permitted by the PERMIT filter.
174 // Use ACL table flow rules here for DENY filtering objectives
175 log.debug("filter objective other than PERMIT currently not supported");
176 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
177 }
178 }
179
180 @Override
181 public void forward(ForwardingObjective fwd) {
182 Collection<FlowRule> rules;
183 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
184
185 rules = processForward(fwd);
186 switch (fwd.op()) {
187 case ADD:
188 rules.stream()
Sho SHIMIZU45906042016-01-13 23:05:54 -0800189 .filter(Objects::nonNull)
Saurav Das822c4e22015-10-23 10:51:11 -0700190 .forEach(flowOpsBuilder::add);
191 break;
192 case REMOVE:
193 rules.stream()
Sho SHIMIZU45906042016-01-13 23:05:54 -0800194 .filter(Objects::nonNull)
Saurav Das822c4e22015-10-23 10:51:11 -0700195 .forEach(flowOpsBuilder::remove);
196 break;
197 default:
198 fail(fwd, ObjectiveError.UNKNOWN);
199 log.warn("Unknown forwarding type {}", fwd.op());
200 }
201
Saurav Das822c4e22015-10-23 10:51:11 -0700202 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
203 @Override
204 public void onSuccess(FlowRuleOperations ops) {
205 pass(fwd);
206 }
207
208 @Override
209 public void onError(FlowRuleOperations ops) {
210 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
211 }
212 }));
Saurav Das822c4e22015-10-23 10:51:11 -0700213 }
214
215 @Override
216 public void next(NextObjective nextObjective) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800217 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
218 switch (nextObjective.op()) {
219 case ADD:
Saurav Das4f980082015-11-05 13:39:15 -0800220 if (nextGroup != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800221 log.warn("Cannot add next {} that already exists in device {}",
222 nextObjective.id(), deviceId);
223 return;
224 }
225 log.debug("Processing NextObjective id{} in dev{} - add group",
226 nextObjective.id(), deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700227 groupHandler.addGroup(nextObjective);
Saurav Das8a0732e2015-11-20 15:27:53 -0800228 break;
229 case ADD_TO_EXISTING:
230 if (nextGroup != null) {
231 log.debug("Processing NextObjective id{} in dev{} - add bucket",
232 nextObjective.id(), deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700233 groupHandler.addBucketToGroup(nextObjective, nextGroup);
Saurav Das4f980082015-11-05 13:39:15 -0800234 } else {
Saurav Das8a0732e2015-11-20 15:27:53 -0800235 // it is possible that group-chain has not been fully created yet
Saurav Das423fe2b2015-12-04 10:52:59 -0800236 log.debug("Waiting to add bucket to group for next-id:{} in dev:{}",
237 nextObjective.id(), deviceId);
238 // by design only one pending bucket is allowed for the group
Charles Chan425854b2016-04-11 15:32:12 -0700239 groupHandler.pendingBuckets.put(nextObjective.id(), nextObjective);
Saurav Das4f980082015-11-05 13:39:15 -0800240 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800241 break;
242 case REMOVE:
243 if (nextGroup == null) {
244 log.warn("Cannot remove next {} that does not exist in device {}",
245 nextObjective.id(), deviceId);
246 return;
247 }
248 log.debug("Processing NextObjective id{} in dev{} - remove group",
249 nextObjective.id(), deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700250 groupHandler.removeGroup(nextObjective, nextGroup);
Saurav Das8a0732e2015-11-20 15:27:53 -0800251 break;
252 case REMOVE_FROM_EXISTING:
253 if (nextGroup == null) {
254 log.warn("Cannot remove from next {} that does not exist in device {}",
255 nextObjective.id(), deviceId);
256 return;
257 }
258 log.debug("Processing NextObjective id{} in dev{} - remove bucket",
259 nextObjective.id(), deviceId);
Charles Chan425854b2016-04-11 15:32:12 -0700260 groupHandler.removeBucketFromGroup(nextObjective, nextGroup);
Saurav Das8a0732e2015-11-20 15:27:53 -0800261 break;
262 default:
Saurav Das4f980082015-11-05 13:39:15 -0800263 log.warn("Unsupported operation {}", nextObjective.op());
Saurav Das822c4e22015-10-23 10:51:11 -0700264 }
265 }
266
267 //////////////////////////////////////
268 // Flow handling
269 //////////////////////////////////////
270
271 /**
272 * As per OFDPA 2.0 TTP, filtering of VLAN ids, MAC addresses (for routing)
273 * and IP addresses configured on switch ports happen in different tables.
274 * Note that IP filtering rules need to be added to the ACL table, as there
275 * is no mechanism to send to controller via IP table.
276 *
277 * @param filt the filtering objective
278 * @param install indicates whether to add or remove the objective
279 * @param applicationId the application that sent this objective
280 */
Saurav Das52025962016-01-28 22:30:01 -0800281 protected void processFilter(FilteringObjective filt,
282 boolean install, ApplicationId applicationId) {
Saurav Das822c4e22015-10-23 10:51:11 -0700283 // This driver only processes filtering criteria defined with switch
284 // ports as the key
285 PortCriterion portCriterion = null;
286 EthCriterion ethCriterion = null;
287 VlanIdCriterion vidCriterion = null;
288 Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
289 if (!filt.key().equals(Criteria.dummy()) &&
290 filt.key().type() == Criterion.Type.IN_PORT) {
291 portCriterion = (PortCriterion) filt.key();
292 } else {
293 log.warn("No key defined in filtering objective from app: {}. Not"
294 + "processing filtering objective", applicationId);
295 fail(filt, ObjectiveError.UNKNOWN);
296 return;
297 }
298 // convert filtering conditions for switch-intfs into flowrules
299 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
300 for (Criterion criterion : filt.conditions()) {
Charles Chan5b9df8d2016-03-28 22:21:40 -0700301 if (criterion.type() == Criterion.Type.ETH_DST ||
302 criterion.type() == Criterion.Type.ETH_DST_MASKED) {
Saurav Das822c4e22015-10-23 10:51:11 -0700303 ethCriterion = (EthCriterion) criterion;
304 } else if (criterion.type() == Criterion.Type.VLAN_VID) {
305 vidCriterion = (VlanIdCriterion) criterion;
306 } else if (criterion.type() == Criterion.Type.IPV4_DST) {
307 ips.add((IPCriterion) criterion);
308 } else {
309 log.error("Unsupported filter {}", criterion);
310 fail(filt, ObjectiveError.UNSUPPORTED);
311 return;
312 }
313 }
314
Saurav Das0e99e2b2015-10-28 12:39:42 -0700315 VlanId assignedVlan = null;
Charles Chane849c192016-01-11 18:28:54 -0800316 if (vidCriterion != null) {
Charles Chand55e84d2016-03-30 17:54:24 -0700317 // Use the VLAN in metadata whenever a metadata is provided
318 if (filt.meta() != null) {
319 assignedVlan = readVlanFromTreatment(filt.meta());
320 // Use the VLAN in criterion if metadata is not present and the traffic is tagged
321 } else if (!vidCriterion.vlanId().equals(VlanId.NONE)) {
Charles Chane849c192016-01-11 18:28:54 -0800322 assignedVlan = vidCriterion.vlanId();
Charles Chand55e84d2016-03-30 17:54:24 -0700323 }
Charles Chane849c192016-01-11 18:28:54 -0800324
Charles Chand55e84d2016-03-30 17:54:24 -0700325 if (assignedVlan == null) {
326 log.error("Driver fails to extract VLAN information. "
327 + "Not proccessing VLAN filters on device {}.", deviceId);
328 log.debug("VLAN ID in criterion={}, metadata={}",
329 readVlanFromTreatment(filt.meta()), vidCriterion.vlanId());
330 fail(filt, ObjectiveError.BADPARAMS);
331 return;
Saurav Das0e99e2b2015-10-28 12:39:42 -0700332 }
333 }
334
Charles Chane849c192016-01-11 18:28:54 -0800335 if (ethCriterion == null || ethCriterion.mac().equals(MacAddress.NONE)) {
Saurav Das822c4e22015-10-23 10:51:11 -0700336 log.debug("filtering objective missing dstMac, cannot program TMAC table");
337 } else {
338 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700339 vidCriterion, assignedVlan,
340 applicationId)) {
Saurav Das822c4e22015-10-23 10:51:11 -0700341 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
342 tmacRule, deviceId);
343 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
344 }
345 }
346
347 if (ethCriterion == null || vidCriterion == null) {
Charles Chane849c192016-01-11 18:28:54 -0800348 log.debug("filtering objective missing dstMac or VLAN, "
349 + "cannot program VLAN Table");
Saurav Das822c4e22015-10-23 10:51:11 -0700350 } else {
Charles Chan14967c22015-12-07 11:11:50 -0800351 /*
352 * NOTE: Separate vlan filtering rules and assignment rules
353 * into different stage in order to guarantee that filtering rules
Saurav Das52025962016-01-28 22:30:01 -0800354 * always go first, as required by ofdpa.
Charles Chan14967c22015-12-07 11:11:50 -0800355 */
356 List<FlowRule> allRules = processVlanIdFilter(
357 portCriterion, vidCriterion, assignedVlan, applicationId);
358 List<FlowRule> filteringRules = new ArrayList<>();
359 List<FlowRule> assignmentRules = new ArrayList<>();
360
361 allRules.forEach(flowRule -> {
362 ExtensionCriterion extCriterion =
363 (ExtensionCriterion) flowRule.selector().getCriterion(Criterion.Type.EXTENSION);
364 VlanId vlanId = ((OfdpaMatchVlanVid) extCriterion.extensionSelector()).vlanId();
Charles Chanbe8aea42016-02-24 12:04:47 -0800365 if (!vlanId.equals(VlanId.NONE)) {
Charles Chan14967c22015-12-07 11:11:50 -0800366 filteringRules.add(flowRule);
367 } else {
368 assignmentRules.add(flowRule);
369 }
370 });
371
372 for (FlowRule filteringRule : filteringRules) {
Saurav Das822c4e22015-10-23 10:51:11 -0700373 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
Charles Chan14967c22015-12-07 11:11:50 -0800374 filteringRule, deviceId);
375 ops = install ? ops.add(filteringRule) : ops.remove(filteringRule);
376 }
377
378 ops.newStage();
379
380 for (FlowRule assignmentRule : assignmentRules) {
381 log.debug("adding VLAN assignment rule in VLAN table: {} for dev: {}",
382 assignmentRule, deviceId);
383 ops = install ? ops.add(assignmentRule) : ops.remove(assignmentRule);
Saurav Das822c4e22015-10-23 10:51:11 -0700384 }
385 }
386
387 for (IPCriterion ipaddr : ips) {
388 // since we ignore port information for IP rules, and the same (gateway) IP
389 // can be configured on multiple ports, we make sure that we send
390 // only a single rule to the switch.
391 if (!sentIpFilters.contains(ipaddr)) {
392 sentIpFilters.add(ipaddr);
393 log.debug("adding IP filtering rules in ACL table {} for dev: {}",
394 ipaddr, deviceId);
395 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
396 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
397 selector.matchEthType(Ethernet.TYPE_IPV4);
398 selector.matchIPDst(ipaddr.ip());
399 treatment.setOutput(PortNumber.CONTROLLER);
400 FlowRule rule = DefaultFlowRule.builder()
401 .forDevice(deviceId)
402 .withSelector(selector.build())
403 .withTreatment(treatment.build())
404 .withPriority(HIGHEST_PRIORITY)
405 .fromApp(applicationId)
406 .makePermanent()
407 .forTable(ACL_TABLE).build();
408 ops = install ? ops.add(rule) : ops.remove(rule);
409 }
410 }
411
412 // apply filtering flow rules
413 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
414 @Override
415 public void onSuccess(FlowRuleOperations ops) {
416 log.info("Applied {} filtering rules in device {}",
417 ops.stages().get(0).size(), deviceId);
418 pass(filt);
419 }
420
421 @Override
422 public void onError(FlowRuleOperations ops) {
423 log.info("Failed to apply all filtering rules in dev {}", deviceId);
424 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
425 }
426 }));
427
428 }
429
430 /**
431 * Allows untagged packets into pipeline by assigning a vlan id.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700432 * Vlan assignment is done by the application.
Saurav Das822c4e22015-10-23 10:51:11 -0700433 * Allows tagged packets into pipeline as per configured port-vlan info.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700434 *
Saurav Das822c4e22015-10-23 10:51:11 -0700435 * @param portCriterion port on device for which this filter is programmed
436 * @param vidCriterion vlan assigned to port, or NONE for untagged
Saurav Das0e99e2b2015-10-28 12:39:42 -0700437 * @param assignedVlan assigned vlan-id for untagged packets
Saurav Das822c4e22015-10-23 10:51:11 -0700438 * @param applicationId for application programming this filter
439 * @return list of FlowRule for port-vlan filters
440 */
441 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
442 VlanIdCriterion vidCriterion,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700443 VlanId assignedVlan,
Saurav Das822c4e22015-10-23 10:51:11 -0700444 ApplicationId applicationId) {
Charles Chan14967c22015-12-07 11:11:50 -0800445 List<FlowRule> rules = new ArrayList<>();
Saurav Das822c4e22015-10-23 10:51:11 -0700446 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
447 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Charles Chan14967c22015-12-07 11:11:50 -0800448 TrafficSelector.Builder preSelector = null;
449 TrafficTreatment.Builder preTreatment = null;
450
Saurav Das4f980082015-11-05 13:39:15 -0800451 treatment.transition(TMAC_TABLE);
452
Saurav Das822c4e22015-10-23 10:51:11 -0700453 if (vidCriterion.vlanId() == VlanId.NONE) {
454 // untagged packets are assigned vlans
Charles Chanbe8aea42016-02-24 12:04:47 -0800455 OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(VlanId.NONE);
Charles Chan14967c22015-12-07 11:11:50 -0800456 selector.extension(ofdpaMatchVlanVid, deviceId);
457 OfdpaSetVlanVid ofdpaSetVlanVid = new OfdpaSetVlanVid(assignedVlan);
458 treatment.extension(ofdpaSetVlanVid, deviceId);
Charles Chan14967c22015-12-07 11:11:50 -0800459
460 preSelector = DefaultTrafficSelector.builder();
461 OfdpaMatchVlanVid preOfdpaMatchVlanVid = new OfdpaMatchVlanVid(assignedVlan);
462 preSelector.extension(preOfdpaMatchVlanVid, deviceId);
463 preTreatment = DefaultTrafficTreatment.builder().transition(TMAC_TABLE);
464
Saurav Das4f980082015-11-05 13:39:15 -0800465 } else {
Charles Chan14967c22015-12-07 11:11:50 -0800466 OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(vidCriterion.vlanId());
467 selector.extension(ofdpaMatchVlanVid, deviceId);
Charles Chand55e84d2016-03-30 17:54:24 -0700468
469 if (!assignedVlan.equals(vidCriterion.vlanId())) {
470 OfdpaSetVlanVid ofdpaSetVlanVid = new OfdpaSetVlanVid(assignedVlan);
471 treatment.extension(ofdpaSetVlanVid, deviceId);
472 }
Saurav Das822c4e22015-10-23 10:51:11 -0700473 }
Saurav Das822c4e22015-10-23 10:51:11 -0700474
475 // ofdpa cannot match on ALL portnumber, so we need to use separate
476 // rules for each port.
Charles Chan14967c22015-12-07 11:11:50 -0800477 List<PortNumber> portnums = new ArrayList<>();
Saurav Das822c4e22015-10-23 10:51:11 -0700478 if (portCriterion.port() == PortNumber.ALL) {
479 for (Port port : deviceService.getPorts(deviceId)) {
480 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
481 portnums.add(port.number());
482 }
483 }
484 } else {
485 portnums.add(portCriterion.port());
486 }
Saurav Das4f980082015-11-05 13:39:15 -0800487
Saurav Das822c4e22015-10-23 10:51:11 -0700488 for (PortNumber pnum : portnums) {
Saurav Das4f980082015-11-05 13:39:15 -0800489 // create rest of flowrule
Saurav Das822c4e22015-10-23 10:51:11 -0700490 selector.matchInPort(pnum);
491 FlowRule rule = DefaultFlowRule.builder()
492 .forDevice(deviceId)
493 .withSelector(selector.build())
494 .withTreatment(treatment.build())
495 .withPriority(DEFAULT_PRIORITY)
496 .fromApp(applicationId)
497 .makePermanent()
498 .forTable(VLAN_TABLE).build();
Charles Chan14967c22015-12-07 11:11:50 -0800499
500 if (preSelector != null) {
501 preSelector.matchInPort(pnum);
502 FlowRule preRule = DefaultFlowRule.builder()
503 .forDevice(deviceId)
504 .withSelector(preSelector.build())
505 .withTreatment(preTreatment.build())
506 .withPriority(DEFAULT_PRIORITY)
507 .fromApp(applicationId)
508 .makePermanent()
509 .forTable(VLAN_TABLE).build();
510 rules.add(preRule);
511 }
512
Saurav Das822c4e22015-10-23 10:51:11 -0700513 rules.add(rule);
514 }
515 return rules;
516 }
517
518 /**
519 * Allows routed packets with correct destination MAC to be directed
520 * to unicast-IP routing table or MPLS forwarding table.
Saurav Das822c4e22015-10-23 10:51:11 -0700521 *
522 * @param portCriterion port on device for which this filter is programmed
523 * @param ethCriterion dstMac of device for which is filter is programmed
524 * @param vidCriterion vlan assigned to port, or NONE for untagged
Saurav Das0e99e2b2015-10-28 12:39:42 -0700525 * @param assignedVlan assigned vlan-id for untagged packets
Saurav Das822c4e22015-10-23 10:51:11 -0700526 * @param applicationId for application programming this filter
527 * @return list of FlowRule for port-vlan filters
528
529 */
530 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
531 EthCriterion ethCriterion,
532 VlanIdCriterion vidCriterion,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700533 VlanId assignedVlan,
Saurav Das822c4e22015-10-23 10:51:11 -0700534 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800535 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
536 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
537 return processEthDstOnlyFilter(ethCriterion, applicationId);
538 }
539
Charles Chan5b9df8d2016-03-28 22:21:40 -0700540 // Multicast MAC
541 if (ethCriterion.mask() != null) {
542 return processMcastEthDstFilter(ethCriterion, applicationId);
543 }
544
Saurav Das822c4e22015-10-23 10:51:11 -0700545 //handling untagged packets via assigned VLAN
546 if (vidCriterion.vlanId() == VlanId.NONE) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700547 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
Saurav Das822c4e22015-10-23 10:51:11 -0700548 }
549 // ofdpa cannot match on ALL portnumber, so we need to use separate
550 // rules for each port.
551 List<PortNumber> portnums = new ArrayList<PortNumber>();
552 if (portCriterion.port() == PortNumber.ALL) {
553 for (Port port : deviceService.getPorts(deviceId)) {
554 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
555 portnums.add(port.number());
556 }
557 }
558 } else {
559 portnums.add(portCriterion.port());
560 }
561
562 List<FlowRule> rules = new ArrayList<FlowRule>();
563 for (PortNumber pnum : portnums) {
Charles Chan14967c22015-12-07 11:11:50 -0800564 OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(vidCriterion.vlanId());
Saurav Das822c4e22015-10-23 10:51:11 -0700565 // for unicast IP packets
566 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
567 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
568 selector.matchInPort(pnum);
Charles Chan14967c22015-12-07 11:11:50 -0800569 selector.extension(ofdpaMatchVlanVid, deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -0700570 selector.matchEthType(Ethernet.TYPE_IPV4);
571 selector.matchEthDst(ethCriterion.mac());
572 treatment.transition(UNICAST_ROUTING_TABLE);
573 FlowRule rule = DefaultFlowRule.builder()
574 .forDevice(deviceId)
575 .withSelector(selector.build())
576 .withTreatment(treatment.build())
577 .withPriority(DEFAULT_PRIORITY)
578 .fromApp(applicationId)
579 .makePermanent()
580 .forTable(TMAC_TABLE).build();
581 rules.add(rule);
582 //for MPLS packets
583 selector = DefaultTrafficSelector.builder();
584 treatment = DefaultTrafficTreatment.builder();
585 selector.matchInPort(pnum);
Charles Chan14967c22015-12-07 11:11:50 -0800586 selector.extension(ofdpaMatchVlanVid, deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -0700587 selector.matchEthType(Ethernet.MPLS_UNICAST);
588 selector.matchEthDst(ethCriterion.mac());
589 treatment.transition(MPLS_TABLE_0);
590 rule = DefaultFlowRule.builder()
591 .forDevice(deviceId)
592 .withSelector(selector.build())
593 .withTreatment(treatment.build())
594 .withPriority(DEFAULT_PRIORITY)
595 .fromApp(applicationId)
596 .makePermanent()
597 .forTable(TMAC_TABLE).build();
598 rules.add(rule);
599 }
600 return rules;
601 }
602
Charles Chan5270ed02016-01-30 23:22:37 -0800603 protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
604 ApplicationId applicationId) {
605 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
606 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
607 selector.matchEthType(Ethernet.TYPE_IPV4);
608 selector.matchEthDst(ethCriterion.mac());
609 treatment.transition(UNICAST_ROUTING_TABLE);
610 FlowRule rule = DefaultFlowRule.builder()
611 .forDevice(deviceId)
612 .withSelector(selector.build())
613 .withTreatment(treatment.build())
614 .withPriority(DEFAULT_PRIORITY)
615 .fromApp(applicationId)
616 .makePermanent()
617 .forTable(TMAC_TABLE).build();
618 return ImmutableList.<FlowRule>builder().add(rule).build();
619 }
620
Charles Chan5b9df8d2016-03-28 22:21:40 -0700621 protected List<FlowRule> processMcastEthDstFilter(EthCriterion ethCriterion,
622 ApplicationId applicationId) {
623 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
624 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
625 selector.matchEthType(Ethernet.TYPE_IPV4);
626 selector.matchEthDstMasked(ethCriterion.mac(), ethCriterion.mask());
627 treatment.transition(MULTICAST_ROUTING_TABLE);
628 FlowRule rule = DefaultFlowRule.builder()
629 .forDevice(deviceId)
630 .withSelector(selector.build())
631 .withTreatment(treatment.build())
632 .withPriority(DEFAULT_PRIORITY)
633 .fromApp(applicationId)
634 .makePermanent()
635 .forTable(TMAC_TABLE).build();
636 return ImmutableList.<FlowRule>builder().add(rule).build();
637 }
638
Saurav Das822c4e22015-10-23 10:51:11 -0700639 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
640 switch (fwd.flag()) {
641 case SPECIFIC:
642 return processSpecific(fwd);
643 case VERSATILE:
644 return processVersatile(fwd);
645 default:
646 fail(fwd, ObjectiveError.UNKNOWN);
647 log.warn("Unknown forwarding flag {}", fwd.flag());
648 }
649 return Collections.emptySet();
650 }
651
652 /**
653 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
654 * ACL table.
655 * @param fwd the forwarding objective of type 'versatile'
656 * @return a collection of flow rules to be sent to the switch. An empty
657 * collection may be returned if there is a problem in processing
658 * the flow rule
659 */
Saurav Das52025962016-01-28 22:30:01 -0800660 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
Saurav Das822c4e22015-10-23 10:51:11 -0700661 log.info("Processing versatile forwarding objective");
Saurav Das822c4e22015-10-23 10:51:11 -0700662
663 EthTypeCriterion ethType =
Saurav Das77b5e902016-01-27 17:01:59 -0800664 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
Saurav Das822c4e22015-10-23 10:51:11 -0700665 if (ethType == null) {
666 log.error("Versatile forwarding objective must include ethType");
667 fail(fwd, ObjectiveError.BADPARAMS);
668 return Collections.emptySet();
669 }
670 if (fwd.nextId() == null && fwd.treatment() == null) {
671 log.error("Forwarding objective {} from {} must contain "
672 + "nextId or Treatment", fwd.selector(), fwd.appId());
Zsolt Haraszti9faab752016-02-17 15:55:20 -0800673 fail(fwd, ObjectiveError.BADPARAMS);
Saurav Das822c4e22015-10-23 10:51:11 -0700674 return Collections.emptySet();
675 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800676
Saurav Das77b5e902016-01-27 17:01:59 -0800677 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
678 fwd.selector().criteria().forEach(criterion -> {
679 if (criterion instanceof VlanIdCriterion) {
680 VlanId vlanId = ((VlanIdCriterion) criterion).vlanId();
681 // ensure that match does not include vlan = NONE as OF-DPA does not
682 // match untagged packets this way in the ACL table.
683 if (vlanId.equals(VlanId.NONE)) {
684 return;
685 }
686 OfdpaMatchVlanVid ofdpaMatchVlanVid =
687 new OfdpaMatchVlanVid(vlanId);
688 sbuilder.extension(ofdpaMatchVlanVid, deviceId);
689 } else {
690 sbuilder.add(criterion);
691 }
692 });
693
Saurav Das822c4e22015-10-23 10:51:11 -0700694 // XXX driver does not currently do type checking as per Tables 65-67 in
695 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
Saurav Das49cb5a12016-01-16 22:54:07 -0800696 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
697 if (fwd.treatment() != null) {
698 for (Instruction ins : fwd.treatment().allInstructions()) {
699 if (ins instanceof OutputInstruction) {
700 OutputInstruction o = (OutputInstruction) ins;
701 if (o.port() == PortNumber.CONTROLLER) {
702 ttBuilder.add(o);
703 } else {
704 log.warn("Only allowed treatments in versatile forwarding "
705 + "objectives are punts to the controller");
706 }
707 } else {
708 log.warn("Cannot process instruction in versatile fwd {}", ins);
709 }
Saurav Das822c4e22015-10-23 10:51:11 -0700710 }
711 }
Saurav Das822c4e22015-10-23 10:51:11 -0700712 if (fwd.nextId() != null) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800713 // overide case
714 NextGroup next = getGroupForNextObjective(fwd.nextId());
715 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
716 // we only need the top level group's key to point the flow to it
717 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
718 if (group == null) {
719 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
720 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
721 fail(fwd, ObjectiveError.GROUPMISSING);
722 return Collections.emptySet();
723 }
724 ttBuilder.deferred().group(group.id());
Saurav Das822c4e22015-10-23 10:51:11 -0700725 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800726
727 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
728 .fromApp(fwd.appId())
729 .withPriority(fwd.priority())
730 .forDevice(deviceId)
Saurav Das77b5e902016-01-27 17:01:59 -0800731 .withSelector(sbuilder.build())
Saurav Das49cb5a12016-01-16 22:54:07 -0800732 .withTreatment(ttBuilder.build())
733 .makePermanent()
734 .forTable(ACL_TABLE);
735 return Collections.singletonList(ruleBuilder.build());
Saurav Das822c4e22015-10-23 10:51:11 -0700736 }
737
738 /**
739 * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table
Saurav Das8a0732e2015-11-20 15:27:53 -0800740 * (unicast or multicast) or the L2 table (mac + vlan) or the MPLS table.
Saurav Das822c4e22015-10-23 10:51:11 -0700741 *
742 * @param fwd the forwarding objective of type 'specific'
743 * @return a collection of flow rules. Typically there will be only one
744 * for this type of forwarding objective. An empty set may be
745 * returned if there is an issue in processing the objective.
746 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800747 protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
Saurav Das4ce45962015-11-24 23:21:05 -0800748 log.trace("Processing specific fwd objective:{} in dev:{} with next:{}",
749 fwd.id(), deviceId, fwd.nextId());
750 boolean isEthTypeObj = isSupportedEthTypeObjective(fwd);
751 boolean isEthDstObj = isSupportedEthDstObjective(fwd);
752
753 if (isEthTypeObj) {
754 return processEthTypeSpecific(fwd);
755 } else if (isEthDstObj) {
756 return processEthDstSpecific(fwd);
757 } else {
758 log.warn("processSpecific: Unsupported forwarding objective "
759 + "criteria fwd:{} in dev:{}", fwd.nextId(), deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -0700760 fail(fwd, ObjectiveError.UNSUPPORTED);
761 return Collections.emptySet();
762 }
Saurav Das4ce45962015-11-24 23:21:05 -0800763 }
764
765 private boolean isSupportedEthTypeObjective(ForwardingObjective fwd) {
766 TrafficSelector selector = fwd.selector();
767 EthTypeCriterion ethType = (EthTypeCriterion) selector
768 .getCriterion(Criterion.Type.ETH_TYPE);
Charles Chan188ebf52015-12-23 00:15:11 -0800769 return !((ethType == null) ||
Saurav Das4ce45962015-11-24 23:21:05 -0800770 ((ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Charles Chan188ebf52015-12-23 00:15:11 -0800771 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)));
Saurav Das4ce45962015-11-24 23:21:05 -0800772 }
773
774 private boolean isSupportedEthDstObjective(ForwardingObjective fwd) {
775 TrafficSelector selector = fwd.selector();
776 EthCriterion ethDst = (EthCriterion) selector
777 .getCriterion(Criterion.Type.ETH_DST);
778 VlanIdCriterion vlanId = (VlanIdCriterion) selector
779 .getCriterion(Criterion.Type.VLAN_VID);
Charles Chan188ebf52015-12-23 00:15:11 -0800780 return !(ethDst == null && vlanId == null);
Saurav Das4ce45962015-11-24 23:21:05 -0800781 }
782
783 /**
784 * Handles forwarding rules to the IP and MPLS tables.
785 *
786 * @param fwd the forwarding objective
787 * @return A collection of flow rules, or an empty set
788 */
789 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
790 TrafficSelector selector = fwd.selector();
791 EthTypeCriterion ethType =
792 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Flavio Castroe10fa242016-01-15 12:43:51 -0800793 boolean defaultRule = false;
794 boolean popMpls = false;
Charles Chan188ebf52015-12-23 00:15:11 -0800795 int forTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800796 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Charles Chan14967c22015-12-07 11:11:50 -0800797 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800798 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
Charles Chan14967c22015-12-07 11:11:50 -0800799
Flavio Castroe10fa242016-01-15 12:43:51 -0800800 /*
801 * NOTE: The switch does not support matching 0.0.0.0/0.
802 * Split it into 0.0.0.0/1 and 128.0.0.0/1
803 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800804 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800805 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700806 if (ipv4Dst.isMulticast()) {
807 if (ipv4Dst.prefixLength() != 32) {
808 log.warn("Multicast specific forwarding objective can only be /32");
809 fail(fwd, ObjectiveError.BADPARAMS);
810 return ImmutableSet.of();
811 }
812 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
813 if (assignedVlan == null) {
814 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
815 fail(fwd, ObjectiveError.BADPARAMS);
816 return ImmutableSet.of();
817 }
818 OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(assignedVlan);
819 filteredSelector.extension(ofdpaMatchVlanVid, deviceId);
820 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
821 forTableId = MULTICAST_ROUTING_TABLE;
822 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
823 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800824 } else {
Charles Chan5b9df8d2016-03-28 22:21:40 -0700825 if (ipv4Dst.prefixLength() > 0) {
826 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
827 } else {
828 filteredSelector.matchEthType(Ethernet.TYPE_IPV4)
829 .matchIPDst(IpPrefix.valueOf("0.0.0.0/1"));
830 complementarySelector.matchEthType(Ethernet.TYPE_IPV4)
831 .matchIPDst(IpPrefix.valueOf("128.0.0.0/1"));
832 defaultRule = true;
833 }
834 forTableId = UNICAST_ROUTING_TABLE;
835 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
836 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800837 }
Charles Chan14967c22015-12-07 11:11:50 -0800838
839 if (fwd.treatment() != null) {
840 for (Instruction instr : fwd.treatment().allInstructions()) {
841 if (instr instanceof L3ModificationInstruction &&
842 ((L3ModificationInstruction) instr).subtype() == L3SubType.DEC_TTL) {
843 tb.deferred().add(instr);
844 }
845 }
846 }
847
Saurav Das8a0732e2015-11-20 15:27:53 -0800848 } else {
849 filteredSelector
850 .matchEthType(Ethernet.MPLS_UNICAST)
851 .matchMplsLabel(((MplsCriterion)
852 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
853 MplsBosCriterion bos = (MplsBosCriterion) selector
854 .getCriterion(Criterion.Type.MPLS_BOS);
855 if (bos != null) {
856 filteredSelector.matchMplsBos(bos.mplsBos());
857 }
858 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800859 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
860 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -0700861
Charles Chan14967c22015-12-07 11:11:50 -0800862 if (fwd.treatment() != null) {
863 for (Instruction instr : fwd.treatment().allInstructions()) {
864 if (instr instanceof L2ModificationInstruction &&
865 ((L2ModificationInstruction) instr).subtype() == L2SubType.MPLS_POP) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800866 popMpls = true;
Charles Chan14967c22015-12-07 11:11:50 -0800867 tb.immediate().add(instr);
868 }
869 if (instr instanceof L3ModificationInstruction &&
870 ((L3ModificationInstruction) instr).subtype() == L3SubType.DEC_TTL) {
871 // FIXME Should modify the app to send the correct DEC_MPLS_TTL instruction
872 tb.immediate().decMplsTtl();
873 }
874 if (instr instanceof L3ModificationInstruction &&
875 ((L3ModificationInstruction) instr).subtype() == L3SubType.TTL_IN) {
876 tb.immediate().add(instr);
877 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800878 }
879 }
880 }
Saurav Das822c4e22015-10-23 10:51:11 -0700881
882 if (fwd.nextId() != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800883 if (forTableId == MPLS_TABLE_1 && !popMpls) {
884 log.warn("SR CONTINUE case cannot be handled as MPLS ECMP "
885 + "is not implemented in OF-DPA yet. Aborting this flow "
886 + "in this device {}", deviceId);
887 // XXX We could convert to forwarding to a single-port, via a
888 // MPLS interface, or a MPLS SWAP (with-same) but that would
889 // have to be handled in the next-objective. Also the pop-mpls
890 // logic used here won't work in non-BoS case.
Saurav Das4ce45962015-11-24 23:21:05 -0800891 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
Saurav Das8a0732e2015-11-20 15:27:53 -0800892 return Collections.emptySet();
893 }
894
Saurav Das423fe2b2015-12-04 10:52:59 -0800895 NextGroup next = getGroupForNextObjective(fwd.nextId());
896 if (next != null) {
897 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
898 // we only need the top level group's key to point the flow to it
899 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
900 if (group == null) {
901 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
902 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
903 fail(fwd, ObjectiveError.GROUPMISSING);
904 return Collections.emptySet();
905 }
906 tb.deferred().group(group.id());
Saurav Das822c4e22015-10-23 10:51:11 -0700907 }
Saurav Das822c4e22015-10-23 10:51:11 -0700908 }
909 tb.transition(ACL_TABLE);
910 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
911 .fromApp(fwd.appId())
912 .withPriority(fwd.priority())
913 .forDevice(deviceId)
Saurav Das8a0732e2015-11-20 15:27:53 -0800914 .withSelector(filteredSelector.build())
915 .withTreatment(tb.build())
916 .forTable(forTableId);
Saurav Das822c4e22015-10-23 10:51:11 -0700917
918 if (fwd.permanent()) {
919 ruleBuilder.makePermanent();
920 } else {
921 ruleBuilder.makeTemporary(fwd.timeout());
922 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800923 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
924 flowRuleCollection.add(ruleBuilder.build());
925 if (defaultRule) {
926 FlowRule.Builder rule = DefaultFlowRule.builder()
927 .fromApp(fwd.appId())
928 .withPriority(fwd.priority())
929 .forDevice(deviceId)
930 .withSelector(complementarySelector.build())
931 .withTreatment(tb.build())
932 .forTable(forTableId);
933 if (fwd.permanent()) {
934 rule.makePermanent();
935 } else {
936 rule.makeTemporary(fwd.timeout());
937 }
938 flowRuleCollection.add(rule.build());
939 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
940 }
Saurav Das822c4e22015-10-23 10:51:11 -0700941
Flavio Castroe10fa242016-01-15 12:43:51 -0800942 return flowRuleCollection;
Saurav Das822c4e22015-10-23 10:51:11 -0700943 }
944
Saurav Das4ce45962015-11-24 23:21:05 -0800945 /**
946 * Handles forwarding rules to the L2 bridging table. Flow actions are not
947 * allowed in the bridging table - instead we use L2 Interface group or
948 * L2 flood group
949 *
950 * @param fwd the forwarding objective
951 * @return A collection of flow rules, or an empty set
952 */
953 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
954 List<FlowRule> rules = new ArrayList<>();
955
956 // Build filtered selector
957 TrafficSelector selector = fwd.selector();
958 EthCriterion ethCriterion = (EthCriterion) selector
959 .getCriterion(Criterion.Type.ETH_DST);
960 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
961 .getCriterion(Criterion.Type.VLAN_VID);
962
963 if (vlanIdCriterion == null) {
964 log.warn("Forwarding objective for bridging requires vlan. Not "
965 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
966 fail(fwd, ObjectiveError.BADPARAMS);
967 return Collections.emptySet();
968 }
969
970 TrafficSelector.Builder filteredSelectorBuilder =
971 DefaultTrafficSelector.builder();
972 // Do not match MacAddress for subnet broadcast entry
973 if (!ethCriterion.mac().equals(MacAddress.NONE)) {
974 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
975 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
976 fwd.id(), fwd.nextId(), deviceId);
977 } else {
978 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
979 + "in dev:{} for vlan:{}",
980 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
981 }
Charles Chan14967c22015-12-07 11:11:50 -0800982 OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(vlanIdCriterion.vlanId());
983 filteredSelectorBuilder.extension(ofdpaMatchVlanVid, deviceId);
Saurav Das4ce45962015-11-24 23:21:05 -0800984 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
985
986 if (fwd.treatment() != null) {
987 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
988 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
989 }
990
991 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
992 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800993 NextGroup next = getGroupForNextObjective(fwd.nextId());
Saurav Das4ce45962015-11-24 23:21:05 -0800994 if (next != null) {
995 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
996 // we only need the top level group's key to point the flow to it
997 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
998 if (group != null) {
999 treatmentBuilder.deferred().group(group.id());
1000 } else {
1001 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
1002 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
1003 fail(fwd, ObjectiveError.GROUPMISSING);
1004 return Collections.emptySet();
1005 }
1006 }
1007 }
1008 treatmentBuilder.immediate().transition(ACL_TABLE);
1009 TrafficTreatment filteredTreatment = treatmentBuilder.build();
1010
1011 // Build bridging table entries
1012 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
1013 flowRuleBuilder.fromApp(fwd.appId())
1014 .withPriority(fwd.priority())
1015 .forDevice(deviceId)
1016 .withSelector(filteredSelector)
1017 .withTreatment(filteredTreatment)
1018 .forTable(BRIDGING_TABLE);
1019 if (fwd.permanent()) {
1020 flowRuleBuilder.makePermanent();
1021 } else {
1022 flowRuleBuilder.makeTemporary(fwd.timeout());
1023 }
1024 rules.add(flowRuleBuilder.build());
1025 return rules;
1026 }
1027
Saurav Das423fe2b2015-12-04 10:52:59 -08001028 protected NextGroup getGroupForNextObjective(Integer nextId) {
1029 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
1030 if (next != null) {
1031 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
1032 if (gkeys != null && !gkeys.isEmpty()) {
1033 return next;
1034 } else {
1035 log.warn("Empty next group found in FlowObjective store for "
1036 + "next-id:{} in dev:{}", nextId, deviceId);
1037 }
1038 } else {
1039 log.warn("next-id {} not found in Flow objective store for dev:{}",
1040 nextId, deviceId);
1041 }
1042 return null;
1043 }
1044
Charles Chan188ebf52015-12-23 00:15:11 -08001045 protected static void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001046 obj.context().ifPresent(context -> context.onSuccess(obj));
Saurav Das822c4e22015-10-23 10:51:11 -07001047 }
1048
Charles Chan188ebf52015-12-23 00:15:11 -08001049 protected static void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001050 obj.context().ifPresent(context -> context.onError(obj, error));
Saurav Das822c4e22015-10-23 10:51:11 -07001051 }
Saurav Das24431192016-03-07 19:13:00 -08001052
Saurav Das24431192016-03-07 19:13:00 -08001053 @Override
1054 public List<String> getNextMappings(NextGroup nextGroup) {
1055 List<String> mappings = new ArrayList<>();
1056 List<Deque<GroupKey>> gkeys = appKryo.deserialize(nextGroup.data());
1057 for (Deque<GroupKey> gkd : gkeys) {
1058 Group lastGroup = null;
Saurav Das8be4e3a2016-03-11 17:19:07 -08001059 StringBuffer gchain = new StringBuffer();
Saurav Das24431192016-03-07 19:13:00 -08001060 for (GroupKey gk : gkd) {
1061 Group g = groupService.getGroup(deviceId, gk);
Saurav Das8be4e3a2016-03-11 17:19:07 -08001062 if (g == null) {
1063 gchain.append(" ERROR").append(" -->");
1064 continue;
1065 }
1066 gchain.append(" 0x").append(Integer.toHexString(g.id().id()))
1067 .append(" -->");
Saurav Das24431192016-03-07 19:13:00 -08001068 lastGroup = g;
1069 }
1070 // add port information for last group in group-chain
1071 for (Instruction i: lastGroup.buckets().buckets().get(0).treatment().allInstructions()) {
1072 if (i instanceof OutputInstruction) {
Saurav Das8be4e3a2016-03-11 17:19:07 -08001073 gchain.append(" port:").append(((OutputInstruction) i).port());
Saurav Das24431192016-03-07 19:13:00 -08001074 }
1075 }
Saurav Das8be4e3a2016-03-11 17:19:07 -08001076 mappings.add(gchain.toString());
Saurav Das24431192016-03-07 19:13:00 -08001077 }
1078 return mappings;
1079 }
Charles Chan5b9df8d2016-03-28 22:21:40 -07001080
1081 protected static VlanId readVlanFromSelector(TrafficSelector selector) {
1082 Criterion criterion = selector.getCriterion(Criterion.Type.VLAN_VID);
1083 return (criterion == null)
1084 ? null : ((VlanIdCriterion) criterion).vlanId();
1085 }
1086
1087 protected static IpPrefix readIpDstFromSelector(TrafficSelector selector) {
1088 Criterion criterion = selector.getCriterion(Criterion.Type.IPV4_DST);
1089 return (criterion == null) ? null : ((IPCriterion) criterion).ip();
1090 }
Charles Chand55e84d2016-03-30 17:54:24 -07001091
1092 private static VlanId readVlanFromTreatment(TrafficTreatment treatment) {
1093 for (Instruction i : treatment.allInstructions()) {
1094 if (i instanceof ModVlanIdInstruction) {
1095 return ((ModVlanIdInstruction) i).vlanId();
1096 }
1097 }
1098 return null;
1099 }
Saurav Das822c4e22015-10-23 10:51:11 -07001100}