blob: dbfe36bfe936b17f6a4587c659a8b776f14832e1 [file] [log] [blame]
Georgios Katsikas70671b32018-07-02 18:47:27 +02001/*
2 * Copyright 2018 Open Networking Foundation
3 *
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.server;
18
Georgios Katsikas70671b32018-07-02 18:47:27 +020019import org.onosproject.drivers.server.devices.nic.NicFlowRule;
20import org.onosproject.drivers.server.devices.nic.NicRxFilter.RxFilter;
21import org.onosproject.net.DeviceId;
Georgios Katsikas042a0fc2018-08-16 18:49:07 +020022import org.onosproject.net.driver.Driver;
23import org.onosproject.net.driver.DriverService;
Georgios Katsikas70671b32018-07-02 18:47:27 +020024import org.onosproject.net.flow.DefaultFlowEntry;
25import org.onosproject.net.flow.FlowEntry;
26import org.onosproject.net.flow.FlowRule;
27import org.onosproject.net.flow.FlowRuleProgrammable;
28import org.onosproject.net.flow.FlowRuleService;
29
Georgios Katsikas042a0fc2018-08-16 18:49:07 +020030import org.slf4j.Logger;
31
Georgios Katsikas13ccba62020-03-18 12:05:03 +010032import com.fasterxml.jackson.databind.JsonNode;
33import com.fasterxml.jackson.databind.ObjectMapper;
34import com.fasterxml.jackson.databind.node.ArrayNode;
35import com.fasterxml.jackson.databind.node.ObjectNode;
36import com.google.common.base.Strings;
37import com.google.common.collect.Sets;
38
Georgios Katsikas70671b32018-07-02 18:47:27 +020039import java.io.ByteArrayInputStream;
40import java.io.IOException;
41import java.io.InputStream;
42import java.util.Collection;
43import java.util.Collections;
Georgios Katsikas332985d2019-01-21 13:23:26 +010044import java.util.Iterator;
Georgios Katsikas042a0fc2018-08-16 18:49:07 +020045import java.util.List;
Georgios Katsikas70671b32018-07-02 18:47:27 +020046import java.util.Map;
47import java.util.Set;
48import java.util.concurrent.ConcurrentHashMap;
49import javax.ws.rs.ProcessingException;
50
51import static com.google.common.base.Preconditions.checkArgument;
52import static com.google.common.base.Preconditions.checkNotNull;
Georgios Katsikas13ccba62020-03-18 12:05:03 +010053import static org.onosproject.drivers.server.Constants.JSON;
54import static org.onosproject.drivers.server.Constants.MSG_DEVICE_ID_NULL;
55import static org.onosproject.drivers.server.Constants.PARAM_ID;
56import static org.onosproject.drivers.server.Constants.PARAM_CPUS;
57import static org.onosproject.drivers.server.Constants.PARAM_NICS;
58import static org.onosproject.drivers.server.Constants.PARAM_NIC_RX_FILTER;
59import static org.onosproject.drivers.server.Constants.PARAM_NIC_RX_FILTER_FD;
60import static org.onosproject.drivers.server.Constants.PARAM_NIC_RX_METHOD;
61import static org.onosproject.drivers.server.Constants.PARAM_RULES;
62import static org.onosproject.drivers.server.Constants.PARAM_RULE_CONTENT;
63import static org.onosproject.drivers.server.Constants.SLASH;
64import static org.onosproject.drivers.server.Constants.URL_RULE_MANAGEMENT;
Georgios Katsikas70671b32018-07-02 18:47:27 +020065import static org.slf4j.LoggerFactory.getLogger;
66
67/**
68 * Manages rules on commodity server devices, by
69 * converting ONOS FlowRule objetcs into
70 * network interface card (NIC) rules and vice versa.
71 */
Georgios Katsikas13ccba62020-03-18 12:05:03 +010072public class FlowRuleProgrammableServerImpl
73 extends BasicServerDriver
Georgios Katsikas70671b32018-07-02 18:47:27 +020074 implements FlowRuleProgrammable {
75
76 private final Logger log = getLogger(getClass());
77
78 /**
Georgios Katsikas042a0fc2018-08-16 18:49:07 +020079 * Driver's property to specify how many rules the controller can remove at once.
80 */
81 private static final String RULE_DELETE_BATCH_SIZE_PROPERTY = "ruleDeleteBatchSize";
Georgios Katsikas70671b32018-07-02 18:47:27 +020082
Georgios Katsikas13ccba62020-03-18 12:05:03 +010083 public FlowRuleProgrammableServerImpl() {
84 super();
85 log.debug("Started");
86 }
87
Georgios Katsikas70671b32018-07-02 18:47:27 +020088 @Override
89 public Collection<FlowEntry> getFlowEntries() {
Georgios Katsikas13ccba62020-03-18 12:05:03 +010090 DeviceId deviceId = getDeviceId();
91 checkNotNull(deviceId, MSG_DEVICE_ID_NULL);
Georgios Katsikas70671b32018-07-02 18:47:27 +020092
93 // Expected FlowEntries installed through ONOS
94 FlowRuleService flowService = getHandler().get(FlowRuleService.class);
95 Iterable<FlowEntry> flowEntries = flowService.getFlowEntries(deviceId);
96
97 // Hit the path that provides the server's flow rules
98 InputStream response = null;
99 try {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100100 response = getController().get(deviceId, URL_RULE_MANAGEMENT, JSON);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200101 } catch (ProcessingException pEx) {
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200102 log.error("Failed to get NIC flow entries from device: {}", deviceId);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200103 return Collections.EMPTY_LIST;
104 }
105
106 // Load the JSON into objects
107 ObjectMapper mapper = new ObjectMapper();
108 ObjectNode objNode = null;
109 try {
110 Map<String, Object> jsonMap = mapper.readValue(response, Map.class);
111 JsonNode jsonNode = mapper.convertValue(jsonMap, JsonNode.class);
112 objNode = (ObjectNode) jsonNode;
113 } catch (IOException ioEx) {
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200114 log.error("Failed to get NIC flow entries from device: {}", deviceId);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200115 return Collections.EMPTY_LIST;
116 }
117
118 if (objNode == null) {
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200119 log.error("Failed to get NIC flow entries from device: {}", deviceId);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200120 return Collections.EMPTY_LIST;
121 }
122
123 JsonNode scsNode = objNode.path(PARAM_RULES);
124
125 // Here we store the trully installed rules
126 Collection<FlowEntry> actualFlowEntries =
127 Sets.<FlowEntry>newConcurrentHashSet();
128
129 for (JsonNode scNode : scsNode) {
130 String scId = get(scNode, PARAM_ID);
131 String rxFilter = get(
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100132 scNode.path(PARAM_NIC_RX_FILTER), PARAM_NIC_RX_METHOD);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200133
134 // Only Flow-based RxFilter is permitted
135 if (RxFilter.getByName(rxFilter) != RxFilter.FLOW) {
136 log.warn("Device with Rx filter {} is not managed by this driver",
137 rxFilter.toString().toUpperCase());
138 continue;
139 }
140
141 // Each device might have multiple NICs
142 for (JsonNode nicNode : scNode.path(PARAM_NICS)) {
Georgios Katsikas70671b32018-07-02 18:47:27 +0200143 JsonNode cpusNode = nicNode.path(PARAM_CPUS);
144
145 // Each NIC can dispatch to multiple CPU cores
146 for (JsonNode cpuNode : cpusNode) {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100147 String cpuId = get(cpuNode, PARAM_ID);
148 JsonNode rulesNode = cpuNode.path(PARAM_RULES);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200149
150 // Multiple rules might correspond to each CPU core
151 for (JsonNode ruleNode : rulesNode) {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100152 long ruleId = ruleNode.path(PARAM_ID).asLong();
Georgios Katsikas70671b32018-07-02 18:47:27 +0200153 String ruleContent = get(ruleNode, PARAM_RULE_CONTENT);
154
155 // Search for this rule ID in ONOS's store
156 FlowRule r = findRuleInFlowEntries(flowEntries, ruleId);
157
158 // Local rule, not present in the controller => Ignore
159 if (r == null) {
160 continue;
161 // Rule trully present in the data plane => Add
162 } else {
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200163 actualFlowEntries.add(new DefaultFlowEntry(
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100164 r, FlowEntry.FlowEntryState.ADDED, 0, 0, 0));
Georgios Katsikas70671b32018-07-02 18:47:27 +0200165 }
166 }
167 }
168 }
169 }
170
171 return actualFlowEntries;
172 }
173
174 @Override
175 public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100176 DeviceId deviceId = getDeviceId();
177 checkNotNull(deviceId, MSG_DEVICE_ID_NULL);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200178
179 // Set of truly-installed rules to be reported
180 Set<FlowRule> installedRules = Sets.<FlowRule>newConcurrentHashSet();
181
182 // Splits the rule set into multiple ones, grouped by traffic class ID
183 Map<String, Set<FlowRule>> rulesPerTc = groupRules(rules);
184
185 // Install NIC rules on a per-traffic class basis
186 for (Map.Entry<String, Set<FlowRule>> entry : rulesPerTc.entrySet()) {
187 String tcId = entry.getKey();
188 Set<FlowRule> tcRuleSet = entry.getValue();
189
190 installedRules.addAll(
191 installNicFlowRules(deviceId, tcId, tcRuleSet)
192 );
193 }
194
195 return installedRules;
196 }
197
198 @Override
199 public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100200 DeviceId deviceId = getDeviceId();
201 checkNotNull(deviceId, MSG_DEVICE_ID_NULL);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200202
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200203 int ruleDeleteBatchSize = getRuleDeleteBatchSizeProperty(deviceId);
204
Georgios Katsikas70671b32018-07-02 18:47:27 +0200205 // Set of truly-removed rules to be reported
206 Set<FlowRule> removedRules = Sets.<FlowRule>newConcurrentHashSet();
207
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200208 List<FlowRule> ruleList = (List) rules;
209 int ruleCount = rules.size();
210 int ruleStart = 0;
211 int processed = 0;
212 int batchNb = 1;
213 while (processed < ruleCount) {
214 String ruleIds = "";
215
216 for (int i = ruleStart; i < ruleCount; i++) {
217 // Batch completed
218 if (i >= (batchNb * ruleDeleteBatchSize)) {
219 break;
220 }
221
222 // TODO: Turn this string into a list and modify removeNicFlowRuleBatch()
223 // Create a comma-separated sequence of rule IDs
224 ruleIds += Long.toString(ruleList.get(i).id().value()) + ",";
225
226 processed++;
Georgios Katsikas70671b32018-07-02 18:47:27 +0200227 }
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200228
229 // Remove last comma
230 ruleIds = ruleIds.substring(0, ruleIds.length() - 1);
231
232 // Remove the entire batch of rules at once
233 if (removeNicFlowRuleBatch(deviceId, ruleIds)) {
234 removedRules.addAll(ruleList.subList(ruleStart, processed));
235 }
236
237 // Prepare for the next batch (if any)
238 batchNb++;
239 ruleStart += ruleDeleteBatchSize;
240 }
Georgios Katsikas70671b32018-07-02 18:47:27 +0200241
242 return removedRules;
243 }
244
245 /**
246 * Groups a set of FlowRules by their traffic class ID.
247 *
248 * @param rules set of NIC rules to install
249 * @return a map of traffic class IDs to their set of NIC rules
250 */
251 private Map<String, Set<FlowRule>> groupRules(Collection<FlowRule> rules) {
252 Map<String, Set<FlowRule>> rulesPerTc =
253 new ConcurrentHashMap<String, Set<FlowRule>>();
254
255 rules.forEach(rule -> {
256 if (!(rule instanceof FlowEntry)) {
Georgios Katsikas6dc11c12018-12-20 08:43:29 +0100257 NicFlowRule nicRule = null;
Georgios Katsikas70671b32018-07-02 18:47:27 +0200258
Georgios Katsikas6dc11c12018-12-20 08:43:29 +0100259 // Only NicFlowRules are accepted
260 try {
261 nicRule = (NicFlowRule) rule;
262 } catch (ClassCastException cEx) {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100263 log.warn("Skipping flow rule not crafted for NIC: {}", rule);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200264 }
265
Georgios Katsikas6dc11c12018-12-20 08:43:29 +0100266 if (nicRule != null) {
267 String tcId = nicRule.trafficClassId();
268
269 // Create a bucket of flow rules for this traffic class
270 if (!rulesPerTc.containsKey(tcId)) {
271 rulesPerTc.put(tcId, Sets.<FlowRule>newConcurrentHashSet());
272 }
273
274 Set<FlowRule> tcRuleSet = rulesPerTc.get(tcId);
275 tcRuleSet.add(nicRule);
276 }
Georgios Katsikas70671b32018-07-02 18:47:27 +0200277 }
278 });
279
280 return rulesPerTc;
281 }
282
283 /**
284 * Searches for a flow rule with certain ID.
285 *
286 * @param flowEntries a list of FlowEntries
287 * @param ruleId a desired rule ID
288 * @return a FlowRule that corresponds to the desired ID or null
289 */
290 private FlowRule findRuleInFlowEntries(
291 Iterable<FlowEntry> flowEntries, long ruleId) {
292 for (FlowEntry fe : flowEntries) {
293 if (fe.id().value() == ruleId) {
294 return (FlowRule) fe;
295 }
296 }
297
298 return null;
299 }
300
301 /**
302 * Installs a set of FlowRules of the same traffic class ID
303 * on a server device.
304 *
305 * @param deviceId target server device ID
306 * @param trafficClassId traffic class ID of the NIC rules
307 * @param rules set of NIC rules to install
308 * @return a set of successfully installed NIC rules
309 */
310 private Collection<FlowRule> installNicFlowRules(
311 DeviceId deviceId, String trafficClassId,
312 Collection<FlowRule> rules) {
Georgios Katsikas332985d2019-01-21 13:23:26 +0100313 int rulesToInstall = rules.size();
314 if (rulesToInstall == 0) {
Georgios Katsikas70671b32018-07-02 18:47:27 +0200315 return Collections.EMPTY_LIST;
316 }
317
318 ObjectMapper mapper = new ObjectMapper();
319
320 // Create the object node to host the list of rules
321 ObjectNode scsObjNode = mapper.createObjectNode();
322
323 // Add the service chain's traffic class ID that requested these rules
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100324 scsObjNode.put(PARAM_ID, trafficClassId);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200325
326 // Create the object node to host the Rx filter method
327 ObjectNode methodObjNode = mapper.createObjectNode();
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100328 methodObjNode.put(PARAM_NIC_RX_METHOD, PARAM_NIC_RX_FILTER_FD);
329 scsObjNode.put(PARAM_NIC_RX_FILTER, methodObjNode);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200330
331 // Map each core to an array of rule IDs and rules
332 Map<Long, ArrayNode> cpuObjSet =
333 new ConcurrentHashMap<Long, ArrayNode>();
334
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200335 String nic = null;
Georgios Katsikas332985d2019-01-21 13:23:26 +0100336 Iterator<FlowRule> it = rules.iterator();
Georgios Katsikas70671b32018-07-02 18:47:27 +0200337
Georgios Katsikas332985d2019-01-21 13:23:26 +0100338 while (it.hasNext()) {
339 NicFlowRule nicRule = (NicFlowRule) it.next();
340 if (nicRule.isFullWildcard() && (rulesToInstall > 1)) {
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100341 log.warn("Skipping wildcard flow rule: {}", nicRule);
Georgios Katsikas332985d2019-01-21 13:23:26 +0100342 it.remove();
Georgios Katsikas6dc11c12018-12-20 08:43:29 +0100343 continue;
344 }
345
Georgios Katsikas70671b32018-07-02 18:47:27 +0200346 long coreIndex = nicRule.cpuCoreIndex();
347
348 // Keep the ID of the target NIC
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200349 if (nic == null) {
350 nic = findNicInterfaceWithPort(deviceId, nicRule.interfaceNumber());
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200351 checkArgument(!Strings.isNullOrEmpty(nic),
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100352 "Attempted to install flow rules in an invalid NIC");
Georgios Katsikas70671b32018-07-02 18:47:27 +0200353 }
354
355 // Create a JSON array for this CPU core
356 if (!cpuObjSet.containsKey(coreIndex)) {
357 cpuObjSet.put(coreIndex, mapper.createArrayNode());
358 }
359
360 // The array of rules that corresponds to this CPU core
361 ArrayNode ruleArrayNode = cpuObjSet.get(coreIndex);
362
363 // Each rule has an ID and a content
364 ObjectNode ruleNode = mapper.createObjectNode();
365 ruleNode.put("ruleId", nicRule.id().value());
366 ruleNode.put("ruleContent", nicRule.ruleBody());
367
368 ruleArrayNode.add(ruleNode);
369 }
370
Georgios Katsikas332985d2019-01-21 13:23:26 +0100371 if (rules.size() == 0) {
372 log.error("Failed to install {} NIC flow rules in device {}", rulesToInstall, deviceId);
373 return Collections.EMPTY_LIST;
374 }
375
Georgios Katsikas70671b32018-07-02 18:47:27 +0200376 ObjectNode nicObjNode = mapper.createObjectNode();
Georgios Katsikas80e0b9f2018-07-21 20:29:18 +0200377 nicObjNode.put("nicName", nic);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200378
379 ArrayNode cpusArrayNode = nicObjNode.putArray(PARAM_CPUS);
380
381 // Convert the map of CPU cores to arrays of rules to JSON
382 for (Map.Entry<Long, ArrayNode> entry : cpuObjSet.entrySet()) {
383 long coreIndex = entry.getKey();
384 ArrayNode ruleArrayNode = entry.getValue();
385
386 ObjectNode cpuObjNode = mapper.createObjectNode();
387 cpuObjNode.put("cpuId", coreIndex);
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100388 cpuObjNode.putArray(PARAM_RULES).addAll(ruleArrayNode);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200389
390 cpusArrayNode.add(cpuObjNode);
391 }
392
393 scsObjNode.putArray(PARAM_NICS).add(nicObjNode);
394
395 // Create the object node to host all the data
396 ObjectNode sendObjNode = mapper.createObjectNode();
397 sendObjNode.putArray(PARAM_RULES).add(scsObjNode);
398
399 // Post the NIC rules to the server
400 int response = getController().post(
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100401 deviceId, URL_RULE_MANAGEMENT,
Georgios Katsikas70671b32018-07-02 18:47:27 +0200402 new ByteArrayInputStream(sendObjNode.toString().getBytes()), JSON);
403
404 // Upon an error, return an empty set of rules
405 if (!checkStatusCode(response)) {
Georgios Katsikas332985d2019-01-21 13:23:26 +0100406 log.error("Failed to install {} NIC flow rules in device {}", rules.size(), deviceId);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200407 return Collections.EMPTY_LIST;
408 }
409
Georgios Katsikas332985d2019-01-21 13:23:26 +0100410 log.info("Successfully installed {}/{} NIC flow rules in device {}",
411 rules.size(), rulesToInstall, deviceId);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200412
413 // .. or all of them
414 return rules;
415 }
416
417 /**
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200418 * Removes a batch of FlowRules from a server device
419 * using a single REST command.
Georgios Katsikas70671b32018-07-02 18:47:27 +0200420 *
421 * @param deviceId target server device ID
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200422 * @param ruleIds a batch of comma-separated NIC rule IDs to be removed
Georgios Katsikas70671b32018-07-02 18:47:27 +0200423 * @return boolean removal status
424 */
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200425 private boolean removeNicFlowRuleBatch(DeviceId deviceId, String ruleIds) {
Georgios Katsikas30bede52018-07-28 14:46:07 +0200426 int response = -1;
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200427 long ruleCount = ruleIds.chars().filter(ch -> ch == ',').count() + 1;
Georgios Katsikas70671b32018-07-02 18:47:27 +0200428
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200429 // Try to remove the rules, although server might be unreachable
Georgios Katsikas30bede52018-07-28 14:46:07 +0200430 try {
431 response = getController().delete(deviceId,
Georgios Katsikas13ccba62020-03-18 12:05:03 +0100432 URL_RULE_MANAGEMENT + SLASH + ruleIds, null, JSON);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200433 } catch (Exception ex) {
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200434 log.error("Failed to remove NIC flow rule batch with {} rules from device {}", ruleCount, deviceId);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200435 return false;
436 }
437
Georgios Katsikas30bede52018-07-28 14:46:07 +0200438 if (!checkStatusCode(response)) {
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200439 log.error("Failed to remove NIC flow rule batch with {} rules from device {}", ruleCount, deviceId);
Georgios Katsikas30bede52018-07-28 14:46:07 +0200440 return false;
441 }
Georgios Katsikas70671b32018-07-02 18:47:27 +0200442
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200443 log.info("Successfully removed NIC flow rule batch with {} rules from device {}", ruleCount, deviceId);
Georgios Katsikas70671b32018-07-02 18:47:27 +0200444 return true;
445 }
446
Georgios Katsikas042a0fc2018-08-16 18:49:07 +0200447 /**
448 * Returns how many rules this driver can delete at once.
449 *
450 * @param deviceId the device's ID to delete rules from
451 * @return rule deletion batch size
452 */
453 private int getRuleDeleteBatchSizeProperty(DeviceId deviceId) {
454 Driver driver = getHandler().get(DriverService.class).getDriver(deviceId);
455 return Integer.parseInt(driver.getProperty(RULE_DELETE_BATCH_SIZE_PROPERTY));
456 }
457
Georgios Katsikas70671b32018-07-02 18:47:27 +0200458}