blob: 4d1f013cac9f7f69376d45b73a5c291d7cb9c116 [file] [log] [blame]
Jovana Vuleta1de61262017-06-14 11:10:29 +02001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Jovana Vuleta1de61262017-06-14 11:10:29 +02003 *
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 */
16
17package org.onosproject.drivers.hp;
18
19import com.google.common.cache.Cache;
20import com.google.common.cache.CacheBuilder;
21import com.google.common.cache.RemovalCause;
22import com.google.common.cache.RemovalNotification;
Jovana Vuleta1de61262017-06-14 11:10:29 +020023import org.onlab.osgi.ServiceDirectory;
Jovana Vuleta1de61262017-06-14 11:10:29 +020024import org.onlab.util.KryoNamespace;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
Alessio Giorgettic1518bb2017-11-17 17:01:26 +010027import org.onosproject.net.Device;
Jovana Vuleta1de61262017-06-14 11:10:29 +020028import org.onosproject.net.DeviceId;
29import org.onosproject.net.behaviour.NextGroup;
30import org.onosproject.net.behaviour.Pipeliner;
31import org.onosproject.net.behaviour.PipelinerContext;
32import org.onosproject.net.device.DeviceService;
33import org.onosproject.net.driver.AbstractHandlerBehaviour;
Jovana Vuleta1de61262017-06-14 11:10:29 +020034import org.onosproject.net.flow.FlowRule;
35import org.onosproject.net.flow.FlowRuleOperations;
36import org.onosproject.net.flow.FlowRuleOperationsContext;
37import org.onosproject.net.flow.FlowRuleService;
38import org.onosproject.net.flow.TrafficSelector;
Alessio Giorgettic1518bb2017-11-17 17:01:26 +010039import org.onosproject.net.flow.DefaultFlowRule;
Jovana Vuleta1de61262017-06-14 11:10:29 +020040import org.onosproject.net.flow.TrafficTreatment;
Alessio Giorgettic1518bb2017-11-17 17:01:26 +010041import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.DefaultTrafficSelector;
Jovana Vuleta1de61262017-06-14 11:10:29 +020043import org.onosproject.net.flow.criteria.Criteria;
44import org.onosproject.net.flow.criteria.Criterion;
45import org.onosproject.net.flow.criteria.EthCriterion;
Jovana Vuleta1de61262017-06-14 11:10:29 +020046import org.onosproject.net.flow.criteria.IPCriterion;
47import org.onosproject.net.flow.criteria.PortCriterion;
48import org.onosproject.net.flow.criteria.VlanIdCriterion;
49import org.onosproject.net.flow.instructions.Instruction;
Alessio Giorgettic1518bb2017-11-17 17:01:26 +010050import org.onosproject.net.flow.instructions.L2ModificationInstruction;
51import org.onosproject.net.flow.instructions.L3ModificationInstruction;
52import org.onosproject.net.flow.instructions.L4ModificationInstruction;
Jovana Vuleta1de61262017-06-14 11:10:29 +020053import org.onosproject.net.flowobjective.FilteringObjective;
54import org.onosproject.net.flowobjective.FlowObjectiveStore;
55import org.onosproject.net.flowobjective.ForwardingObjective;
56import org.onosproject.net.flowobjective.NextObjective;
57import org.onosproject.net.flowobjective.Objective;
58import org.onosproject.net.flowobjective.ObjectiveError;
Alessio Giorgettic1518bb2017-11-17 17:01:26 +010059import org.onosproject.net.group.Group;
Jovana Vuleta1de61262017-06-14 11:10:29 +020060import org.onosproject.net.group.GroupService;
61import org.onosproject.net.meter.MeterService;
alessioff124ad2018-11-13 13:25:51 +010062import org.onosproject.store.serializers.KryoNamespaces;
Jovana Vuleta1de61262017-06-14 11:10:29 +020063import org.slf4j.Logger;
64
Alessio Giorgettic1518bb2017-11-17 17:01:26 +010065import java.util.Set;
alessioff124ad2018-11-13 13:25:51 +010066import java.util.HashSet;
67import java.util.Collection;
68import java.util.Collections;
69import java.util.List;
Jovana Vuleta1de61262017-06-14 11:10:29 +020070import java.util.concurrent.TimeUnit;
71
72import static org.onosproject.net.flow.FlowRule.Builder;
73import static org.onosproject.net.flowobjective.Objective.Operation.ADD;
74import static org.slf4j.LoggerFactory.getLogger;
75
Jovana Vuleta1de61262017-06-14 11:10:29 +020076/**
77 * Abstraction of the HP pipeline handler.
Alessio Giorgettic1518bb2017-11-17 17:01:26 +010078 * Possibly compliant with all HP switches: tested with HP3800 (v2 module) and HP3500 (v1 module).
79 *
80 * These switches supports multiple OpenFlow instances.
81 * Each instance can be created with different pipeline models.
82 * This driver refers to OpenFlow instances created with "pipeline-model standard-match"
83 *
84 * With this model Table 100 is used for all entries that can be processed in hardware,
85 * whereas table 200 is used for entries processed in software.
86 *
87 * Trying to install a flow entries only supported in software in table 100 generates
88 * an OpenFlow error message from the switch.
89 *
90 * Installation of a flow entry supported in hardware in table 200 is allowed. But it strongly
91 * degrades forwarding performance.
92 *
93 * ---------------------------------------------
94 * --- SELECTION OF PROPER TABLE ID ---
95 * --- from device manual OpenFlow v1.3 for firmware 16.04 - (Appendix A)
96 * ---------------------------------------------
97 * --- Hardware differences between v1, v2 and v3 modules affect which features are supported
98 * in hardware/software. In this driver "TableIdForForwardingObjective()" function selects the
99 * proper table ID considering the hardware features of the device and the actual FlowObjective.
100 *
101 * ---------------------------------------------
102 * --- HPE switches support OpenFlow version 1.3.1 with following limitations.
103 * --- from device manual OpenFlow v1.3 for firmware 16.04 - (Appendix A)
104 *
105 *** UNSUPPORTED FLOW MATCHES --- (implemented using unsupported_criteria)
106 * ---------------------------------------------
107 * - METADATA - DONE
108 * - IP_ECN - DONE
109 * - SCTP_SRC, SCTP_DST - DONE
110 * - IPV6_ND_SLL, IPV6_ND_TLL - DONE
111 * - MPLS_LABEL, MPLS_TC, MPLS_BOS - DONE
112 * - PBB_ISID - DONE
113 * - TUNNEL_ID - DONE
114 * - IPV6_EXTHDR - DONE
115 *
116 *** UNSUPPORTED ACTIONS ---
117 * ---------------------------------------------
118 * - METADATA - DONE
119 * - QUEUE - DONE
120 * - OFPP_TABLE action - TODO
121 * - MPLS actions: Push-MPLS, Pop-MPLS, Set-MPLS TTL, Decrement MPLS TTL - DONE
122 * - Push-PBB, Pop-PBB actions - TODO
123 * - Copy TTL inwards/outwards actions - DONE
124 * - Decrement IP TTL - DONE
125 *
126 * ---------------------------------------------
127 * --- OTHER UNSUPPORTED FEATURES ---
128 * --- from device manual OpenFlow v1.3 for firmware 16.04
129 * ---------------------------------------------
130 * - Port commands: OFPPC_NO_STP, OFPPC_NO_RECV, OFPPC_NO_RECV_STP, OFPPC_NO_FWD - TODO
131 * - Handling of IP Fragments: OFPC_IP_REASM, OFPC_FRAG_REASM - TODO
132 *
133 * TODO MINOR: include above actions in the lists of unsupported features
alessioff124ad2018-11-13 13:25:51 +0100134 * TODO MINOR: check pre-requites in flow match
135 *
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100136 *
137 * With current implementation, in case of unsupported features a WARNING message in generated
138 * in the ONOS log, but FlowRule is sent anyway to the device.
139 * The device will reply with an OFP_ERROR message.
140 * Use "debug openflow events" and "debug openflow errors" on the device to locally
141 * visualize detailed information on the specific error.
142 *
143 * TODO MAJOR: use OFP_TABLE_FEATURE messages to automate learning of unsupported features
144 *
Jovana Vuleta1de61262017-06-14 11:10:29 +0200145 */
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100146
Jovana Vuleta1de61262017-06-14 11:10:29 +0200147public abstract class AbstractHPPipeline extends AbstractHandlerBehaviour implements Pipeliner {
148
Jovana Vuleta1de61262017-06-14 11:10:29 +0200149 protected static final String APPLICATION_ID = "org.onosproject.drivers.hp.HPPipeline";
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100150
151 protected static final int HP_TABLE_ZERO = 0;
152 protected static final int HP_HARDWARE_TABLE = 100;
153 protected static final int HP_SOFTWARE_TABLE = 200;
154
Jovana Vuleta1de61262017-06-14 11:10:29 +0200155 public static final int CACHE_ENTRY_EXPIRATION_PERIOD = 20;
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100156
Jovana Vuleta1de61262017-06-14 11:10:29 +0200157 private final Logger log = getLogger(getClass());
158 protected FlowRuleService flowRuleService;
159 protected GroupService groupService;
160 protected MeterService meterService;
161 protected FlowObjectiveStore flowObjectiveStore;
162 protected DeviceId deviceId;
163 protected ApplicationId appId;
164 protected DeviceService deviceService;
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100165 protected Device device;
166 protected String deviceHwVersion;
Jovana Vuleta1de61262017-06-14 11:10:29 +0200167 protected KryoNamespace appKryo = new KryoNamespace.Builder()
alessioff124ad2018-11-13 13:25:51 +0100168 .register(KryoNamespaces.API)
Jovana Vuleta1de61262017-06-14 11:10:29 +0200169 .build("AbstractHPPipeline");
170 private ServiceDirectory serviceDirectory;
171 private CoreService coreService;
172 private Cache<Integer, NextObjective> pendingAddNext = CacheBuilder.newBuilder()
173 .expireAfterWrite(CACHE_ENTRY_EXPIRATION_PERIOD, TimeUnit.SECONDS)
174 .removalListener((RemovalNotification<Integer, NextObjective> notification) -> {
175 if (notification.getCause() == RemovalCause.EXPIRED) {
176 notification.getValue().context()
177 .ifPresent(c -> c.onError(notification.getValue(),
178 ObjectiveError.FLOWINSTALLATIONFAILED));
179 }
180 }).build();
181
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100182 /** Lists of unsupported features (firmware version K 16.04)
183 * If a FlowObjective uses one of these features a warning log message is generated.
184 */
185 protected Set<Criterion.Type> unsupportedCriteria = new HashSet<>();
186 protected Set<Instruction.Type> unsupportedInstructions = new HashSet<>();
187 protected Set<L2ModificationInstruction.L2SubType> unsupportedL2mod = new HashSet<>();
188 protected Set<L3ModificationInstruction.L3SubType> unsupportedL3mod = new HashSet<>();
189
190 /** Lists of Criteria and Instructions supported in hardware
191 * If a FlowObjective uses one of these features the FlowRule is intalled in HP_SOFTWARE_TABLE.
192 */
193 protected Set<Criterion.Type> hardwareCriteria = new HashSet<>();
194 protected Set<Instruction.Type> hardwareInstructions = new HashSet<>();
195 protected Set<L2ModificationInstruction.L2SubType> hardwareInstructionsL2mod = new HashSet<>();
196 protected Set<L3ModificationInstruction.L3SubType> hardwareInstructionsL3mod = new HashSet<>();
197 protected Set<L4ModificationInstruction.L4SubType> hardwareInstructionsL4mod = new HashSet<>();
198 protected Set<Group.Type> hardwareGroups = new HashSet<>();
199
Jovana Vuleta1de61262017-06-14 11:10:29 +0200200 /**
201 * Sets default table id.
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100202 * Using this solution all flow rules are installed on the "default" table
Jovana Vuleta1de61262017-06-14 11:10:29 +0200203 *
204 * @param ruleBuilder flow rule builder to be set table id
205 * @return flow rule builder with set table id for flow
206 */
207 protected abstract FlowRule.Builder setDefaultTableIdForFlowObjective(Builder ruleBuilder);
208
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100209 /**
210 * Return the proper table ID depending on the specific ForwardingObjective.
211 *
212 * HP switches supporting openflow have 3 tables (Pipeline Model: Standard Match)
213 * Table 0 is just a shortcut to table 100
214 * Table 100/200 are respectively used for rules processed in HARDWARE/SOFTWARE
215 *
alessioff124ad2018-11-13 13:25:51 +0100216 * @param selector TrafficSelector including flow match
217 * @param treatment TrafficTreatment including instructions/actions
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100218 * @return table id
219 */
alessioff124ad2018-11-13 13:25:51 +0100220 protected abstract int tableIdForForwardingObjective(TrafficSelector selector, TrafficTreatment treatment);
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100221
222 /**
223 * Return TRUE if ForwardingObjective fwd includes unsupported features.
224 *
alessioff124ad2018-11-13 13:25:51 +0100225 * @param selector TrafficSelector including flow match
226 * @param treatment TrafficTreatment including instructions/actions
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100227 * @return boolean
228 */
alessioff124ad2018-11-13 13:25:51 +0100229 protected abstract boolean checkUnSupportedFeatures(TrafficSelector selector, TrafficTreatment treatment);
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100230
Jovana Vuleta1de61262017-06-14 11:10:29 +0200231 @Override
232 public void init(DeviceId deviceId, PipelinerContext context) {
Jovana Vuleta1de61262017-06-14 11:10:29 +0200233 this.deviceId = deviceId;
234
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100235 serviceDirectory = context.directory();
Jovana Vuleta1de61262017-06-14 11:10:29 +0200236 coreService = serviceDirectory.get(CoreService.class);
237 flowRuleService = serviceDirectory.get(FlowRuleService.class);
238 groupService = serviceDirectory.get(GroupService.class);
239 meterService = serviceDirectory.get(MeterService.class);
240 deviceService = serviceDirectory.get(DeviceService.class);
241 flowObjectiveStore = context.store();
242
243 appId = coreService.registerApplication(APPLICATION_ID);
244
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100245 device = deviceService.getDevice(deviceId);
246 deviceHwVersion = device.hwVersion();
247
248 //Initialization of model specific features
alessioff124ad2018-11-13 13:25:51 +0100249 log.debug("HP Driver - Initializing unsupported features for switch {}", deviceHwVersion);
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100250 initUnSupportedFeatures();
251
252 log.debug("HP Driver - Initializing features supported in hardware");
253 initHardwareCriteria();
254 initHardwareInstructions();
255
256 log.debug("HP Driver - Initializing pipeline");
257 installHPTableZero();
258 installHPHardwareTable();
259 installHPSoftwareTable();
Jovana Vuleta1de61262017-06-14 11:10:29 +0200260 }
261
262 /**
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100263 * UnSupported features are specific of each model.
Jovana Vuleta1de61262017-06-14 11:10:29 +0200264 */
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100265 protected abstract void initUnSupportedFeatures();
266
267 /**
268 * Criteria supported in hardware are specific of each model.
269 */
270 protected abstract void initHardwareCriteria();
271
272 /**
273 * Instructions supported in hardware are specific of each model.
274 */
275 protected abstract void initHardwareInstructions();
276
277 /**
278 * HP Table 0 initialization.
279 * Installs rule goto HP_HARDWARE_TABLE in HP_TABLE_ZERO
280 */
281 private void installHPTableZero() {
282 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
283 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
284
285 treatment.transition(HP_HARDWARE_TABLE);
286
287 FlowRule rule = DefaultFlowRule.builder().forDevice(this.deviceId)
288 .withSelector(selector.build())
289 .withTreatment(treatment.build())
290 .withPriority(0)
291 .fromApp(appId)
292 .makePermanent()
293 .forTable(HP_TABLE_ZERO)
294 .build();
295
296 this.applyRules(true, rule);
297 }
298
299 /**
300 * HP hardware table initialization.
301 * Installs rule goto HP_SOFTWARE_TABLE in HP_HARDWARE_TABLE
302 */
303 private void installHPHardwareTable() {
304 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
305
306 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
307 //treatment.setOutput(PortNumber.NORMAL);
308 treatment.transition(HP_SOFTWARE_TABLE);
309
310 FlowRule rule = DefaultFlowRule.builder().forDevice(this.deviceId)
311 .withSelector(selector.build())
312 .withTreatment(treatment.build())
313 .withPriority(0)
314 .fromApp(appId)
315 .makePermanent()
316 .forTable(HP_HARDWARE_TABLE)
317 .build();
318
319 this.applyRules(true, rule);
320 }
321
322 /**
323 * Applies FlowRule.
324 * Installs or removes FlowRule.
325 *
326 * @param install - whether to install or remove rule
327 * @param rule - the rule to be installed or removed
328 */
329 private void applyRules(boolean install, FlowRule rule) {
330 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
331
332 ops = install ? ops.add(rule) : ops.remove(rule);
333 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
334 @Override
335 public void onSuccess(FlowRuleOperations ops) {
alessioff124ad2018-11-13 13:25:51 +0100336 log.trace("HP Driver: - applyRules onSuccess rule {}", rule);
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100337 }
338
339 @Override
340 public void onError(FlowRuleOperations ops) {
alessioff124ad2018-11-13 13:25:51 +0100341 log.trace("HP Driver: applyRules onError rule: " + rule);
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100342 }
343 }));
344 }
345
346 /**
347 * HP software table initialization.
348 * No rules required.
349 */
350 private void installHPSoftwareTable() {}
Jovana Vuleta1de61262017-06-14 11:10:29 +0200351
352 protected void pass(Objective obj) {
353 obj.context().ifPresent(context -> context.onSuccess(obj));
354 }
355
356 protected void fail(Objective obj, ObjectiveError error) {
357 obj.context().ifPresent(context -> context.onError(obj, error));
358 }
359
360 @Override
361 public void forward(ForwardingObjective fwd) {
362
363 if (fwd.treatment() != null) {
alessioff124ad2018-11-13 13:25:51 +0100364 /* If UNSUPPORTED features included in ForwardingObjective a warning message is generated.
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100365 * FlowRule is anyway sent to the device, device will reply with an OFP_ERROR.
366 * Moreover, checkUnSupportedFeatures function generates further warnings specifying
367 * each unsupported feature.
alessioff124ad2018-11-13 13:25:51 +0100368 */
369 if (checkUnSupportedFeatures(fwd.selector(), fwd.treatment())) {
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100370 log.warn("HP Driver - specified ForwardingObjective contains UNSUPPORTED FEATURES");
Jovana Vuleta1de61262017-06-14 11:10:29 +0200371 }
372
alessioff124ad2018-11-13 13:25:51 +0100373 // Deal with SPECIFIC and VERSATILE in the same manner.
374 // Create the FlowRule starting from the ForwardingObjective
Jovana Vuleta1de61262017-06-14 11:10:29 +0200375 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
376 .forDevice(deviceId)
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100377 .withSelector(fwd.selector())
378 .withTreatment(fwd.treatment())
Jovana Vuleta1de61262017-06-14 11:10:29 +0200379 .withPriority(fwd.priority())
380 .fromApp(fwd.appId());
381
alessioff124ad2018-11-13 13:25:51 +0100382 // Determine the table to be used depends on selector, treatment and specific switch hardware
383 ruleBuilder.forTable(tableIdForForwardingObjective(fwd.selector(), fwd.treatment()));
Jovana Vuleta1de61262017-06-14 11:10:29 +0200384
385 if (fwd.permanent()) {
386 ruleBuilder.makePermanent();
387 } else {
388 ruleBuilder.makeTemporary(fwd.timeout());
389 }
390
alessioff124ad2018-11-13 13:25:51 +0100391 log.debug("HP Driver - installing ForwadingObjective arrived with treatment {}", fwd);
Jovana Vuleta1de61262017-06-14 11:10:29 +0200392 installObjective(ruleBuilder, fwd);
393
394 } else {
395 NextObjective nextObjective;
396 NextGroup next;
397 TrafficTreatment treatment;
398 if (fwd.op() == ADD) {
399 // Give a try to the cache. Doing an operation
400 // on the store seems to be very expensive.
401 nextObjective = pendingAddNext.getIfPresent(fwd.nextId());
402 // If the next objective is not present
403 // We will try with the store
404 if (nextObjective == null) {
405 next = flowObjectiveStore.getNextGroup(fwd.nextId());
406 // We verify that next was in the store and then de-serialize
407 // the treatment in order to re-build the flow rule.
408 if (next == null) {
409 fwd.context().ifPresent(c -> c.onError(fwd, ObjectiveError.GROUPMISSING));
410 return;
411 }
412 treatment = appKryo.deserialize(next.data());
413 } else {
414 pendingAddNext.invalidate(fwd.nextId());
alessioff124ad2018-11-13 13:25:51 +0100415 treatment = getTreatment(nextObjective);
416 if (treatment == null) {
417 fwd.context().ifPresent(c -> c.onError(fwd, ObjectiveError.UNSUPPORTED));
418 return;
419 }
Jovana Vuleta1de61262017-06-14 11:10:29 +0200420 }
421 } else {
422 // We get the NextGroup from the remove operation.
423 // Doing an operation on the store seems to be very expensive.
alessioff124ad2018-11-13 13:25:51 +0100424 next = flowObjectiveStore.getNextGroup(fwd.nextId());
425 treatment = (next != null) ? appKryo.deserialize(next.data()) : null;
Jovana Vuleta1de61262017-06-14 11:10:29 +0200426 }
alessioff124ad2018-11-13 13:25:51 +0100427
Jovana Vuleta1de61262017-06-14 11:10:29 +0200428 // If the treatment is null we cannot re-build the original flow
429 if (treatment == null) {
430 fwd.context().ifPresent(c -> c.onError(fwd, ObjectiveError.GROUPMISSING));
431 return;
432 }
433 // Finally we build the flow rule and push to the flowrule subsystem.
434 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
435 .forDevice(deviceId)
436 .withSelector(fwd.selector())
437 .fromApp(fwd.appId())
438 .withPriority(fwd.priority())
439 .withTreatment(treatment);
alessioff124ad2018-11-13 13:25:51 +0100440
441 /* If UNSUPPORTED features included in ForwardingObjective a warning message is generated.
442 * FlowRule is anyway sent to the device, device will reply with an OFP_ERROR.
443 * Moreover, checkUnSupportedFeatures function generates further warnings specifying
444 * each unsupported feature.
445 */
446 if (checkUnSupportedFeatures(fwd.selector(), treatment)) {
447 log.warn("HP Driver - specified ForwardingObjective contains UNSUPPORTED FEATURES");
448 }
449
450 //Table to be used depends on the specific switch hardware and ForwardingObjective
451 ruleBuilder.forTable(tableIdForForwardingObjective(fwd.selector(), treatment));
452
Jovana Vuleta1de61262017-06-14 11:10:29 +0200453 if (fwd.permanent()) {
454 ruleBuilder.makePermanent();
455 } else {
456 ruleBuilder.makeTemporary(fwd.timeout());
457 }
alessioff124ad2018-11-13 13:25:51 +0100458
459 log.debug("HP Driver - installing ForwadingObjective arrived with NULL treatment (intent)");
Jovana Vuleta1de61262017-06-14 11:10:29 +0200460 installObjective(ruleBuilder, fwd);
461 }
462 }
463
464 /**
465 * Installs objective.
466 *
467 * @param ruleBuilder flow rule builder used to build rule from objective
468 * @param objective objective to be installed
469 */
470 protected void installObjective(FlowRule.Builder ruleBuilder, Objective objective) {
471 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
472
473 switch (objective.op()) {
474 case ADD:
alessioff124ad2018-11-13 13:25:51 +0100475 log.trace("HP Driver - Requested ADD of objective to device " + deviceId);
476 flowBuilder.add(ruleBuilder.build());
Jovana Vuleta1de61262017-06-14 11:10:29 +0200477 break;
478 case REMOVE:
alessioff124ad2018-11-13 13:25:51 +0100479 log.trace("HP Driver - Requested REMOVE of objective to device " + deviceId);
480 flowBuilder.remove(ruleBuilder.build());
Jovana Vuleta1de61262017-06-14 11:10:29 +0200481 break;
482 default:
alessioff124ad2018-11-13 13:25:51 +0100483 log.debug("HP Driver - Unknown operation {}", objective.op());
Jovana Vuleta1de61262017-06-14 11:10:29 +0200484 }
485
486 flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
487 @Override
488 public void onSuccess(FlowRuleOperations ops) {
489 objective.context().ifPresent(context -> context.onSuccess(objective));
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100490 log.trace("HP Driver - Installed objective " + objective.toString());
Jovana Vuleta1de61262017-06-14 11:10:29 +0200491 }
492
493 @Override
494 public void onError(FlowRuleOperations ops) {
495 objective.context()
496 .ifPresent(context -> context.onError(objective, ObjectiveError.FLOWINSTALLATIONFAILED));
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100497 log.trace("HP Driver - Objective installation failed" + objective.toString());
Jovana Vuleta1de61262017-06-14 11:10:29 +0200498 }
499 }));
500 }
501
502 @Override
503 public void next(NextObjective nextObjective) {
504 switch (nextObjective.op()) {
505 case ADD:
alessioff124ad2018-11-13 13:25:51 +0100506 log.debug("HP driver: NextObjective ADDED");
Jovana Vuleta1de61262017-06-14 11:10:29 +0200507 // We insert the value in the cache
508 pendingAddNext.put(nextObjective.id(), nextObjective);
509 // Then in the store, this will unblock the queued fwd obj
510 flowObjectiveStore.putNextGroup(
511 nextObjective.id(),
512 new SingleGroup(nextObjective.next().iterator().next())
513 );
514 break;
515 case REMOVE:
alessioff124ad2018-11-13 13:25:51 +0100516 log.debug("HP driver: NextObjective REMOVED");
517 NextGroup next = flowObjectiveStore.removeNextGroup(nextObjective.id());
518 if (next == null) {
519 nextObjective.context().ifPresent(context -> context.onError(nextObjective,
520 ObjectiveError.GROUPMISSING));
521 return;
522 }
Jovana Vuleta1de61262017-06-14 11:10:29 +0200523 break;
524 default:
alessioff124ad2018-11-13 13:25:51 +0100525 log.debug("Unsupported operation {}", nextObjective.op());
Jovana Vuleta1de61262017-06-14 11:10:29 +0200526 }
527 nextObjective.context().ifPresent(context -> context.onSuccess(nextObjective));
528 }
529
530 @Override
531 public List<String> getNextMappings(NextGroup nextGroup) {
532 //TODO: to be implemented
alessioff124ad2018-11-13 13:25:51 +0100533 return Collections.emptyList();
Jovana Vuleta1de61262017-06-14 11:10:29 +0200534 }
535
536 @Override
537 public void filter(FilteringObjective filteringObjective) {
538 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
539 processFilter(filteringObjective,
540 filteringObjective.op() == Objective.Operation.ADD,
541 filteringObjective.appId());
542 } else {
543 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
544 }
545 }
546
Daniele Moro06aac702021-07-19 22:39:22 +0200547 @Override
548 public void purgeAll(ApplicationId appId) {
549 flowRuleService.purgeFlowRules(deviceId, appId);
550 groupService.purgeGroupEntries(deviceId, appId);
551 meterService.purgeMeters(deviceId, appId);
552 }
553
Jovana Vuleta1de61262017-06-14 11:10:29 +0200554 /**
alessioff124ad2018-11-13 13:25:51 +0100555 * Gets traffic treatment from a next objective.
556 * Merge traffic treatments from next objective if the next objective is
557 * BROADCAST type and contains multiple traffic treatments.
558 * Returns first treatment from next objective if the next objective is
559 * SIMPLE type and it contains only one treatment.
560 *
561 * @param nextObjective the next objective
562 * @return the treatment from next objective; null if not supported
563 */
564 private TrafficTreatment getTreatment(NextObjective nextObjective) {
565 Collection<TrafficTreatment> treatments = nextObjective.next();
566 switch (nextObjective.type()) {
567 case SIMPLE:
568 if (treatments.size() != 1) {
569 log.error("Next Objectives of type SIMPLE should have only " +
570 "one traffic treatment. NexObjective: {}",
571 nextObjective.toString());
572 return null;
573 }
574 return treatments.iterator().next();
575 case BROADCAST:
576 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
577 treatments.forEach(builder::addTreatment);
578 return builder.build();
579 default:
580 log.error("Unsupported next objective type {}.", nextObjective.type());
581 return null;
582 }
583 }
584
585 /**
Jovana Vuleta1de61262017-06-14 11:10:29 +0200586 * Filter processing and installation.
587 * Processes and installs filtering rules.
588 *
589 * @param filt
590 * @param install
591 * @param applicationId
592 */
593 private void processFilter(FilteringObjective filt, boolean install,
594 ApplicationId applicationId) {
595 // This driver only processes filtering criteria defined with switch
596 // ports as the key
597 PortCriterion port;
598 if (!filt.key().equals(Criteria.dummy()) &&
599 filt.key().type() == Criterion.Type.IN_PORT) {
600 port = (PortCriterion) filt.key();
601 } else {
602 log.warn("No key defined in filtering objective from app: {}. Not"
603 + "processing filtering objective", applicationId);
604 fail(filt, ObjectiveError.UNKNOWN);
605 return;
606 }
607 // convert filtering conditions for switch-intfs into flowrules
608 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
609 for (Criterion c : filt.conditions()) {
610 if (c.type() == Criterion.Type.ETH_DST) {
611 EthCriterion eth = (EthCriterion) c;
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100612 FlowRule.Builder rule = processEthFilter(filt, eth, port);
Jovana Vuleta1de61262017-06-14 11:10:29 +0200613 rule.forDevice(deviceId)
614 .fromApp(applicationId);
615 ops = install ? ops.add(rule.build()) : ops.remove(rule.build());
616
617 } else if (c.type() == Criterion.Type.VLAN_VID) {
618 VlanIdCriterion vlan = (VlanIdCriterion) c;
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100619 FlowRule.Builder rule = processVlanFilter(filt, vlan, port);
Jovana Vuleta1de61262017-06-14 11:10:29 +0200620 rule.forDevice(deviceId)
621 .fromApp(applicationId);
622 ops = install ? ops.add(rule.build()) : ops.remove(rule.build());
623
624 } else if (c.type() == Criterion.Type.IPV4_DST) {
625 IPCriterion ip = (IPCriterion) c;
626 FlowRule.Builder rule = processIpFilter(filt, ip, port);
627 rule.forDevice(deviceId)
628 .fromApp(applicationId);
629 ops = install ? ops.add(rule.build()) : ops.remove(rule.build());
630
631 } else {
632 log.warn("Driver does not currently process filtering condition"
633 + " of type: {}", c.type());
634 fail(filt, ObjectiveError.UNSUPPORTED);
635 }
636 }
637 // apply filtering flow rules
638 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
639 @Override
640 public void onSuccess(FlowRuleOperations ops) {
641 pass(filt);
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100642 log.trace("HP Driver - Applied filtering rules");
Jovana Vuleta1de61262017-06-14 11:10:29 +0200643 }
644
645 @Override
646 public void onError(FlowRuleOperations ops) {
647 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100648 log.trace("HP Driver - Failed to apply filtering rules");
Jovana Vuleta1de61262017-06-14 11:10:29 +0200649 }
650 }));
651 }
652
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100653 protected abstract Builder processEthFilter(FilteringObjective filt,
Jovana Vuleta1de61262017-06-14 11:10:29 +0200654 EthCriterion eth, PortCriterion port);
655
Alessio Giorgettic1518bb2017-11-17 17:01:26 +0100656 protected abstract Builder processVlanFilter(FilteringObjective filt,
Jovana Vuleta1de61262017-06-14 11:10:29 +0200657 VlanIdCriterion vlan, PortCriterion port);
658
659 protected abstract Builder processIpFilter(FilteringObjective filt,
660 IPCriterion ip, PortCriterion port);
661
662 private class SingleGroup implements NextGroup {
663
664 private TrafficTreatment nextActions;
665
666 SingleGroup(TrafficTreatment next) {
667 this.nextActions = next;
668 }
669
670 @Override
671 public byte[] data() {
672 return appKryo.serialize(nextActions);
673 }
674
675 public TrafficTreatment treatment() {
676 return nextActions;
677 }
678
679 }
680
681
682}