blob: ac9c38ac3e5d9d62488bf523b4ba6ac2eff02718 [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Thomas Vachuska58de4162015-09-10 16:15:33 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Saurav Dasdecd7a62015-05-16 22:39:47 -070016package org.onosproject.driver.pipeline;
17
Saurav Dasdecd7a62015-05-16 22:39:47 -070018import org.onlab.osgi.ServiceDirectory;
Jonathan Hart63eeac32016-06-20 15:55:16 -070019import org.onlab.packet.EthType;
Saurav Dasdecd7a62015-05-16 22:39:47 -070020import org.onlab.packet.Ethernet;
Jonathan Hart29be97d2016-02-02 14:23:48 -080021import org.onlab.packet.IpPrefix;
Saurav Dasdecd7a62015-05-16 22:39:47 -070022import org.onlab.packet.VlanId;
23import org.onlab.util.KryoNamespace;
24import org.onosproject.core.ApplicationId;
25import org.onosproject.core.CoreService;
26import org.onosproject.net.DeviceId;
Jonathan Hart63eeac32016-06-20 15:55:16 -070027import org.onosproject.net.PortNumber;
Saurav Dasdecd7a62015-05-16 22:39:47 -070028import org.onosproject.net.behaviour.NextGroup;
29import org.onosproject.net.behaviour.Pipeliner;
30import org.onosproject.net.behaviour.PipelinerContext;
31import org.onosproject.net.driver.AbstractHandlerBehaviour;
32import org.onosproject.net.flow.DefaultFlowRule;
33import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.FlowRule;
36import org.onosproject.net.flow.FlowRuleOperations;
37import org.onosproject.net.flow.FlowRuleOperationsContext;
38import org.onosproject.net.flow.FlowRuleService;
39import org.onosproject.net.flow.TrafficSelector;
40import org.onosproject.net.flow.TrafficTreatment;
41import org.onosproject.net.flow.criteria.Criteria;
42import org.onosproject.net.flow.criteria.Criterion;
43import org.onosproject.net.flow.criteria.EthCriterion;
44import org.onosproject.net.flow.criteria.EthTypeCriterion;
45import org.onosproject.net.flow.criteria.IPCriterion;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053046import org.onosproject.net.flow.criteria.IPProtocolCriterion;
47import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
Saurav Dasdecd7a62015-05-16 22:39:47 -070048import org.onosproject.net.flow.criteria.PortCriterion;
49import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das49cb5a12016-01-16 22:54:07 -080050import org.onosproject.net.flow.instructions.Instruction;
51import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Saurav Dasdecd7a62015-05-16 22:39:47 -070052import org.onosproject.net.flowobjective.FilteringObjective;
53import org.onosproject.net.flowobjective.FlowObjectiveStore;
54import org.onosproject.net.flowobjective.ForwardingObjective;
55import org.onosproject.net.flowobjective.NextObjective;
56import org.onosproject.net.flowobjective.Objective;
57import org.onosproject.net.flowobjective.ObjectiveError;
Saurav Dasdecd7a62015-05-16 22:39:47 -070058import org.onosproject.store.serializers.KryoNamespaces;
Jonathan Harte54bdbf2015-11-17 11:29:37 -080059import org.slf4j.Logger;
60
61import java.util.ArrayList;
62import java.util.Collection;
63import java.util.Collections;
Saurav Das24431192016-03-07 19:13:00 -080064import java.util.List;
Sho SHIMIZU45906042016-01-13 23:05:54 -080065import java.util.Objects;
Jonathan Harte54bdbf2015-11-17 11:29:37 -080066
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053067import static org.onlab.packet.Ethernet.TYPE_IPV4;
68import static org.onlab.packet.ICMP6.ECHO_REPLY;
69import static org.onlab.packet.ICMP6.ECHO_REQUEST;
70import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Jonathan Hart29be97d2016-02-02 14:23:48 -080071import static org.onlab.util.Tools.delay;
Jonathan Harte54bdbf2015-11-17 11:29:37 -080072import static org.slf4j.LoggerFactory.getLogger;
Saurav Dasdecd7a62015-05-16 22:39:47 -070073
74/**
75 * Simple 2-Table Pipeline for Software/NPU based routers. This pipeline
76 * does not forward IP traffic to next-hop groups. Instead it forwards traffic
77 * using OF FlowMod actions.
78 */
79public class SoftRouterPipeline extends AbstractHandlerBehaviour implements Pipeliner {
80
81 protected static final int FILTER_TABLE = 0;
82 protected static final int FIB_TABLE = 1;
83
84 private static final int DROP_PRIORITY = 0;
85 private static final int DEFAULT_PRIORITY = 0x8000;
86 private static final int HIGHEST_PRIORITY = 0xffff;
87
88 private ServiceDirectory serviceDirectory;
89 protected FlowRuleService flowRuleService;
90 private CoreService coreService;
91 private FlowObjectiveStore flowObjectiveStore;
92 protected DeviceId deviceId;
93 protected ApplicationId appId;
94 private ApplicationId driverId;
Saurav Dasdecd7a62015-05-16 22:39:47 -070095
96 private KryoNamespace appKryo = new KryoNamespace.Builder()
Jonathan Hart888eeda2016-05-20 13:42:26 -070097 .register(KryoNamespaces.API)
98 .register(DummyGroup.class)
99 .build();
Saurav Dasdecd7a62015-05-16 22:39:47 -0700100
101 private final Logger log = getLogger(getClass());
102
103 @Override
104 public void init(DeviceId deviceId, PipelinerContext context) {
105 this.serviceDirectory = context.directory();
106 this.deviceId = deviceId;
107 coreService = serviceDirectory.get(CoreService.class);
108 flowRuleService = serviceDirectory.get(FlowRuleService.class);
109 flowObjectiveStore = context.store();
110 driverId = coreService.registerApplication(
Jonathan Harte54bdbf2015-11-17 11:29:37 -0800111 "org.onosproject.driver.SoftRouterPipeline");
Jonathan Hart6344f572015-12-15 08:26:25 -0800112
Saurav Dasdecd7a62015-05-16 22:39:47 -0700113 initializePipeline();
114 }
115
116 @Override
117 public void filter(FilteringObjective filteringObjective) {
118 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
119 processFilter(filteringObjective,
120 filteringObjective.op() == Objective.Operation.ADD,
121 filteringObjective.appId());
122 } else {
123 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
124 }
125 }
126
127 @Override
128 public void forward(ForwardingObjective fwd) {
129 Collection<FlowRule> rules;
130 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
131
132 rules = processForward(fwd);
133 switch (fwd.op()) {
134 case ADD:
135 rules.stream()
Sho SHIMIZU45906042016-01-13 23:05:54 -0800136 .filter(Objects::nonNull)
Saurav Dasdecd7a62015-05-16 22:39:47 -0700137 .forEach(flowOpsBuilder::add);
138 break;
139 case REMOVE:
140 rules.stream()
Sho SHIMIZU45906042016-01-13 23:05:54 -0800141 .filter(Objects::nonNull)
Saurav Dasdecd7a62015-05-16 22:39:47 -0700142 .forEach(flowOpsBuilder::remove);
143 break;
144 default:
145 fail(fwd, ObjectiveError.UNKNOWN);
146 log.warn("Unknown forwarding type {}", fwd.op());
147 }
148
149
150 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
151 @Override
152 public void onSuccess(FlowRuleOperations ops) {
153 pass(fwd);
154 }
155
156 @Override
157 public void onError(FlowRuleOperations ops) {
158 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
159 }
160 }));
161
162 }
163
164 @Override
165 public void next(NextObjective nextObjective) {
166 switch (nextObjective.type()) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530167 case SIMPLE:
168 Collection<TrafficTreatment> treatments = nextObjective.next();
169 if (treatments.size() != 1) {
170 log.error("Next Objectives of type Simple should only have a "
171 + "single Traffic Treatment. Next Objective Id:{}", nextObjective.id());
172 fail(nextObjective, ObjectiveError.BADPARAMS);
173 return;
174 }
175 processSimpleNextObjective(nextObjective);
176 break;
177 case HASHED:
178 case BROADCAST:
179 case FAILOVER:
180 fail(nextObjective, ObjectiveError.UNSUPPORTED);
181 log.warn("Unsupported next objective type {}", nextObjective.type());
182 break;
183 default:
184 fail(nextObjective, ObjectiveError.UNKNOWN);
185 log.warn("Unknown next objective type {}", nextObjective.type());
Saurav Dasdecd7a62015-05-16 22:39:47 -0700186 }
187 }
188
189 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800190 obj.context().ifPresent(context -> context.onSuccess(obj));
Saurav Dasdecd7a62015-05-16 22:39:47 -0700191 }
192
193 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800194 obj.context().ifPresent(context -> context.onError(obj, error));
Saurav Dasdecd7a62015-05-16 22:39:47 -0700195 }
196
Saurav Dasdecd7a62015-05-16 22:39:47 -0700197 private void initializePipeline() {
198 //Drop rules for both tables
199 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
200 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
201 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
202
203 treatment.drop();
204
205 FlowRule rule = DefaultFlowRule.builder()
206 .forDevice(deviceId)
207 .withSelector(selector.build())
208 .withTreatment(treatment.build())
209 .withPriority(DROP_PRIORITY)
210 .fromApp(driverId)
211 .makePermanent()
212 .forTable(FILTER_TABLE)
213 .build();
214 ops = ops.add(rule);
215
216 rule = DefaultFlowRule.builder().forDevice(deviceId)
217 .withSelector(selector.build())
218 .withTreatment(treatment.build())
219 .withPriority(DROP_PRIORITY)
220 .fromApp(driverId)
221 .makePermanent()
222 .forTable(FIB_TABLE)
223 .build();
224 ops = ops.add(rule);
225
226 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
227 @Override
228 public void onSuccess(FlowRuleOperations ops) {
229 log.info("Provisioned drop rules in both tables");
230 }
231
232 @Override
233 public void onError(FlowRuleOperations ops) {
234 log.info("Failed to provision drop rules");
235 }
236 }));
237 }
238
239 private void processFilter(FilteringObjective filt, boolean install,
240 ApplicationId applicationId) {
241 // This driver only processes filtering criteria defined with switch
242 // ports as the key
Jonathan Hart6344f572015-12-15 08:26:25 -0800243 PortCriterion p;
244 EthCriterion e = null;
245 VlanIdCriterion v = null;
246
Saurav Dasdecd7a62015-05-16 22:39:47 -0700247 if (!filt.key().equals(Criteria.dummy()) &&
248 filt.key().type() == Criterion.Type.IN_PORT) {
249 p = (PortCriterion) filt.key();
250 } else {
251 log.warn("No key defined in filtering objective from app: {}. Not"
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530252 + "processing filtering objective", applicationId);
Saurav Dasdecd7a62015-05-16 22:39:47 -0700253 fail(filt, ObjectiveError.UNKNOWN);
254 return;
255 }
256
257 // convert filtering conditions for switch-intfs into flowrules
258 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
259 for (Criterion c : filt.conditions()) {
gauravadc90042016-05-09 23:17:05 +0530260 if (c.type() == Criterion.Type.ETH_DST ||
261 c.type() == Criterion.Type.ETH_DST_MASKED) {
Saurav Dasdecd7a62015-05-16 22:39:47 -0700262 e = (EthCriterion) c;
263 } else if (c.type() == Criterion.Type.VLAN_VID) {
264 v = (VlanIdCriterion) c;
Saurav Dasdecd7a62015-05-16 22:39:47 -0700265 } else {
266 log.error("Unsupported filter {}", c);
267 fail(filt, ObjectiveError.UNSUPPORTED);
268 return;
269 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530270
Saurav Dasdecd7a62015-05-16 22:39:47 -0700271 }
272
Jonathan Hartf8035d32016-06-16 16:23:26 -0700273 log.debug("Modifying Port/VLAN/MAC filtering rules in filter table: {}/{}/{}",
Saurav Dasdecd7a62015-05-16 22:39:47 -0700274 p.port(), v.vlanId(), e.mac());
275 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
276 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
277 selector.matchInPort(p.port());
Jonathan Hart6344f572015-12-15 08:26:25 -0800278
gauravadc90042016-05-09 23:17:05 +0530279 //Multicast MAC
280 if (e.mask() != null) {
281 selector.matchEthDstMasked(e.mac(), e.mask());
282 } else {
283 selector.matchEthDst(e.mac());
284 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800285 selector.matchVlanId(v.vlanId());
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530286 selector.matchEthType(TYPE_IPV4);
Jonathan Hartca47cd72015-12-13 12:31:09 -0800287 if (!v.vlanId().equals(VlanId.NONE)) {
288 treatment.popVlan();
289 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800290 treatment.transition(FIB_TABLE);
Saurav Dasdecd7a62015-05-16 22:39:47 -0700291 FlowRule rule = DefaultFlowRule.builder()
292 .forDevice(deviceId)
293 .withSelector(selector.build())
294 .withTreatment(treatment.build())
295 .withPriority(DEFAULT_PRIORITY)
296 .fromApp(applicationId)
297 .makePermanent()
298 .forTable(FILTER_TABLE).build();
Saurav Dasdecd7a62015-05-16 22:39:47 -0700299
Saurav Dasdecd7a62015-05-16 22:39:47 -0700300 ops = install ? ops.add(rule) : ops.remove(rule);
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530301 // FIXME IPv6 in the multicast use case.
302 // Filtering rules for IPv6.
303 if (e.mask() == null) {
304 selector = DefaultTrafficSelector.builder();
305 selector.matchInPort(p.port());
306 selector.matchEthDst(e.mac());
307 selector.matchVlanId(v.vlanId());
308 selector.matchEthType(Ethernet.TYPE_IPV6);
309 if (!v.vlanId().equals(VlanId.NONE)) {
310 treatment.popVlan();
311 }
312 treatment.transition(FIB_TABLE);
313 rule = DefaultFlowRule.builder()
314 .forDevice(deviceId)
315 .withSelector(selector.build())
316 .withTreatment(treatment.build())
317 .withPriority(DEFAULT_PRIORITY)
318 .fromApp(applicationId)
319 .makePermanent()
320 .forTable(FILTER_TABLE).build();
321
322 ops = install ? ops.add(rule) : ops.remove(rule);
323 }
Saurav Dasdecd7a62015-05-16 22:39:47 -0700324 // apply filtering flow rules
325 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
326 @Override
327 public void onSuccess(FlowRuleOperations ops) {
328 log.info("Applied filtering rules");
329 pass(filt);
330 }
331
332 @Override
333 public void onError(FlowRuleOperations ops) {
334 log.info("Failed to apply filtering rules");
335 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
336 }
337 }));
338 }
339
340 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
341 switch (fwd.flag()) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530342 case SPECIFIC:
343 return processSpecific(fwd);
344 case VERSATILE:
345 return processVersatile(fwd);
346 default:
347 fail(fwd, ObjectiveError.UNKNOWN);
348 log.warn("Unknown forwarding flag {}", fwd.flag());
Saurav Dasdecd7a62015-05-16 22:39:47 -0700349 }
350 return Collections.emptySet();
351 }
352
353 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800354 * SoftRouter has a single versatile table - the filter table.
355 * This table can be used to filter entries that reach the next table (FIB table).
356 * It can also be used to punt packets to the controller and/or bypass
357 * the FIB table to forward out of a port.
Saurav Dasdecd7a62015-05-16 22:39:47 -0700358 *
359 * @param fwd The forwarding objective of type versatile
360 * @return A collection of flow rules meant to be delivered to the flowrule
361 * subsystem. May return empty collection in case of failures.
362 */
363 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800364 log.debug("Received versatile fwd: to next:{}", fwd.nextId());
Jonathan Hart6344f572015-12-15 08:26:25 -0800365 Collection<FlowRule> flowrules = new ArrayList<>();
Saurav Das49cb5a12016-01-16 22:54:07 -0800366 if (fwd.nextId() == null && fwd.treatment() == null) {
367 log.error("Forwarding objective {} from {} must contain "
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530368 + "nextId or Treatment", fwd.selector(), fwd.appId());
Saurav Das49cb5a12016-01-16 22:54:07 -0800369 return Collections.emptySet();
370 }
Jonathan Hart63eeac32016-06-20 15:55:16 -0700371
372 int tableId = FILTER_TABLE;
373
374 // A punt rule for IP traffic should be directed to the FIB table
375 // so that it only takes effect if the packet misses the FIB rules
376 if (fwd.treatment() != null && containsPunt(fwd.treatment()) &&
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530377 fwd.selector() != null && matchesIp(fwd.selector()) &&
378 !matchesControlTraffic(fwd.selector())) {
Jonathan Hart63eeac32016-06-20 15:55:16 -0700379 tableId = FIB_TABLE;
380 }
381
Saurav Das49cb5a12016-01-16 22:54:07 -0800382 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
383 if (fwd.treatment() != null) {
384 fwd.treatment().immediate().forEach(ins -> ttBuilder.add(ins));
385 }
386 //convert nextId to flow actions
387 if (fwd.nextId() != null) {
388 // only acceptable value is output to port
389 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
390 if (next == null) {
391 log.error("next-id {} does not exist in store", fwd.nextId());
392 return Collections.emptySet();
393 }
394 TrafficTreatment nt = appKryo.deserialize(next.data());
395 if (nt == null) {
396 log.error("Error in deserializing next-id {}", fwd.nextId());
397 return Collections.emptySet();
398 }
399 for (Instruction ins : nt.allInstructions()) {
400 if (ins instanceof OutputInstruction) {
401 ttBuilder.add(ins);
402 }
403 }
404 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800405
406 FlowRule rule = DefaultFlowRule.builder()
407 .withSelector(fwd.selector())
Saurav Das49cb5a12016-01-16 22:54:07 -0800408 .withTreatment(ttBuilder.build())
Jonathan Hart63eeac32016-06-20 15:55:16 -0700409 .forTable(tableId)
Jonathan Hart6344f572015-12-15 08:26:25 -0800410 .makePermanent()
411 .forDevice(deviceId)
412 .fromApp(fwd.appId())
413 .withPriority(fwd.priority())
414 .build();
415
416 flowrules.add(rule);
417
Saurav Dasdecd7a62015-05-16 22:39:47 -0700418 return flowrules;
419 }
420
Jonathan Hart63eeac32016-06-20 15:55:16 -0700421 private boolean containsPunt(TrafficTreatment treatment) {
422 return treatment.immediate().stream()
423 .anyMatch(i -> i.type().equals(Instruction.Type.OUTPUT)
424 && ((OutputInstruction) i).port().equals(PortNumber.CONTROLLER));
425 }
426
427 private boolean matchesIp(TrafficSelector selector) {
428 EthTypeCriterion c = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530429 return c != null && (c.ethType().equals(EthType.EtherType.IPV4.ethType()) ||
430 c.ethType().equals(EthType.EtherType.IPV6.ethType()));
431 }
432
433 private boolean matchesControlTraffic(TrafficSelector selector) {
434 EthTypeCriterion c = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
435 if (c != null && c.ethType().equals(EthType.EtherType.ARP.ethType())) {
436 return true;
437 } else if (c != null && c.ethType().equals(EthType.EtherType.IPV6.ethType())) {
438 IPProtocolCriterion i = (IPProtocolCriterion) selector.getCriterion(Criterion.Type.IP_PROTO);
439 if (i != null && i.protocol() == PROTOCOL_ICMP6) {
440 Icmpv6TypeCriterion ic = (Icmpv6TypeCriterion) selector.getCriterion(Criterion.Type.ICMPV6_TYPE);
441 if (ic.icmpv6Type() != ECHO_REQUEST && ic.icmpv6Type() != ECHO_REPLY) {
442 return true;
443 }
444 }
445 }
446 return false;
Jonathan Hart63eeac32016-06-20 15:55:16 -0700447 }
448
Saurav Dasdecd7a62015-05-16 22:39:47 -0700449 /**
450 * SoftRouter has a single specific table - the FIB Table. It emulates
451 * LPM matching of dstIP by using higher priority flows for longer prefixes.
452 * Flows are forwarded using flow-actions
453 *
454 * @param fwd The forwarding objective of type simple
455 * @return A collection of flow rules meant to be delivered to the flowrule
456 * subsystem. Typically the returned collection has a single flowrule.
457 * May return empty collection in case of failures.
458 *
459 */
460 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800461 log.debug("Processing specific forwarding objective to next:{}", fwd.nextId());
Saurav Dasdecd7a62015-05-16 22:39:47 -0700462 TrafficSelector selector = fwd.selector();
463 EthTypeCriterion ethType =
464 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
465 // XXX currently supporting only the L3 unicast table
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530466 if (ethType == null || (ethType.ethType().toShort() != TYPE_IPV4
467 && ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Dasdecd7a62015-05-16 22:39:47 -0700468 fail(fwd, ObjectiveError.UNSUPPORTED);
469 return Collections.emptySet();
470 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530471 //We build the selector according the eth type.
472 IpPrefix ipPrefix;
473 TrafficSelector.Builder filteredSelector;
474 if (ethType.ethType().toShort() == TYPE_IPV4) {
475 ipPrefix = ((IPCriterion)
476 selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Saurav Dasdecd7a62015-05-16 22:39:47 -0700477
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530478 filteredSelector = DefaultTrafficSelector.builder()
479 .matchEthType(TYPE_IPV4);
480 } else {
481 ipPrefix = ((IPCriterion)
482 selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
Jonathan Hart29be97d2016-02-02 14:23:48 -0800483
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530484 filteredSelector = DefaultTrafficSelector.builder()
485 .matchEthType(Ethernet.TYPE_IPV6);
486 }
487 // If the prefix is different from the default via.
Jonathan Hart29be97d2016-02-02 14:23:48 -0800488 if (ipPrefix.prefixLength() != 0) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530489 if (ethType.ethType().toShort() == TYPE_IPV4) {
490 filteredSelector.matchIPDst(ipPrefix);
491 } else {
492 filteredSelector.matchIPv6Dst(ipPrefix);
493 }
Jonathan Hart29be97d2016-02-02 14:23:48 -0800494 }
Saurav Dasdecd7a62015-05-16 22:39:47 -0700495
496 TrafficTreatment tt = null;
497 if (fwd.nextId() != null) {
498 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
499 if (next == null) {
500 log.error("next-id {} does not exist in store", fwd.nextId());
501 return Collections.emptySet();
502 }
503 tt = appKryo.deserialize(next.data());
504 if (tt == null) {
505 log.error("Error in deserializing next-id {}", fwd.nextId());
506 return Collections.emptySet();
507 }
508 }
509
510 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
511 .fromApp(fwd.appId())
512 .withPriority(fwd.priority())
513 .forDevice(deviceId)
Jonathan Hart29be97d2016-02-02 14:23:48 -0800514 .withSelector(filteredSelector.build());
Jonathan Hart3930f632015-10-19 12:12:51 -0700515
516 if (tt != null) {
517 ruleBuilder.withTreatment(tt);
518 }
Saurav Dasdecd7a62015-05-16 22:39:47 -0700519
520 if (fwd.permanent()) {
521 ruleBuilder.makePermanent();
522 } else {
523 ruleBuilder.makeTemporary(fwd.timeout());
524 }
525
526 ruleBuilder.forTable(FIB_TABLE);
527 return Collections.singletonList(ruleBuilder.build());
528 }
529
530 /**
531 * Next Objectives are stored as dummy groups for retrieval later
532 * when Forwarding Objectives reference the next objective id. At that point
533 * the dummy group is fetched from the distributed store and the enclosed
534 * treatment is applied as a flow rule action.
535 *
alshabibcaf1ca22015-06-25 15:18:16 -0700536 * @param nextObj the next objective of type simple
Saurav Dasdecd7a62015-05-16 22:39:47 -0700537 */
538 private void processSimpleNextObjective(NextObjective nextObj) {
539 // Simple next objective has a single treatment (not a collection)
Saurav Das49cb5a12016-01-16 22:54:07 -0800540 log.debug("Received nextObj {}", nextObj.id());
541 // delay processing to emulate group creation
542 delay(50);
Saurav Das6c44a632015-05-30 22:05:22 -0700543 TrafficTreatment treatment = nextObj.next().iterator().next();
Saurav Dasdecd7a62015-05-16 22:39:47 -0700544 flowObjectiveStore.putNextGroup(nextObj.id(),
Saurav Das6c44a632015-05-30 22:05:22 -0700545 new DummyGroup(treatment));
Saurav Dasdecd7a62015-05-16 22:39:47 -0700546 }
547
Saurav Dasdecd7a62015-05-16 22:39:47 -0700548 private class DummyGroup implements NextGroup {
549 TrafficTreatment nextActions;
550
551 public DummyGroup(TrafficTreatment next) {
552 this.nextActions = next;
553 }
554
555 @Override
556 public byte[] data() {
557 return appKryo.serialize(nextActions);
558 }
559
560 }
561
Saurav Das24431192016-03-07 19:13:00 -0800562 @Override
563 public List<String> getNextMappings(NextGroup nextGroup) {
564 // nextObjectives converted to flow-actions not groups
565 return Collections.emptyList();
566 }
567
Saurav Dasdecd7a62015-05-16 22:39:47 -0700568}