blob: 352eca87d8f86c5e61fd7abc4630ba4b6ac68592 [file] [log] [blame]
Frank Wang0e805082017-07-21 14:37:35 +08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Frank Wang0e805082017-07-21 14:37:35 +08003 *
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
Andrea Campanella0288c872017-08-07 18:32:51 +020017package org.onosproject.drivers.p4runtime;
Frank Wang0e805082017-07-21 14:37:35 +080018
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +053019import com.google.common.cache.CacheBuilder;
20import com.google.common.cache.CacheLoader;
Carmelo Cascone3da671a2018-02-12 10:43:35 -080021import com.google.common.cache.LoadingCache;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020022import com.google.common.collect.ImmutableList;
23import com.google.common.collect.Lists;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020024import io.grpc.StatusRuntimeException;
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080025import org.onlab.util.SharedExecutors;
26import org.onosproject.drivers.p4runtime.mirror.P4RuntimeTableMirror;
27import org.onosproject.drivers.p4runtime.mirror.TimedEntry;
Frank Wang0e805082017-07-21 14:37:35 +080028import org.onosproject.net.flow.DefaultFlowEntry;
29import org.onosproject.net.flow.FlowEntry;
30import org.onosproject.net.flow.FlowRule;
31import org.onosproject.net.flow.FlowRuleProgrammable;
Carmelo Cascone87892e22017-11-13 16:01:29 -080032import org.onosproject.net.pi.model.PiCounterId;
Frank Wang0e805082017-07-21 14:37:35 +080033import org.onosproject.net.pi.model.PiPipelineInterpreter;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020034import org.onosproject.net.pi.model.PiPipelineModel;
Carmelo Cascone87892e22017-11-13 16:01:29 -080035import org.onosproject.net.pi.model.PiTableId;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020036import org.onosproject.net.pi.model.PiTableModel;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020037import org.onosproject.net.pi.runtime.PiCounterCellData;
38import org.onosproject.net.pi.runtime.PiCounterCellId;
Frank Wang0e805082017-07-21 14:37:35 +080039import org.onosproject.net.pi.runtime.PiTableEntry;
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080040import org.onosproject.net.pi.runtime.PiTableEntryHandle;
41import org.onosproject.net.pi.service.PiFlowRuleTranslator;
42import org.onosproject.net.pi.service.PiTranslatedEntity;
Carmelo Cascone326ad2d2017-11-28 18:09:13 -080043import org.onosproject.net.pi.service.PiTranslationException;
Frank Wang0e805082017-07-21 14:37:35 +080044import org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType;
Frank Wang0e805082017-07-21 14:37:35 +080045
46import java.util.Collection;
47import java.util.Collections;
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +053048import java.util.List;
Carmelo Cascone3da671a2018-02-12 10:43:35 -080049import java.util.Map;
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080050import java.util.Optional;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020051import java.util.Set;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020052import java.util.concurrent.ExecutionException;
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +053053import java.util.concurrent.TimeUnit;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020054import java.util.concurrent.locks.Lock;
55import java.util.concurrent.locks.ReentrantLock;
Carmelo Casconefe99be92017-09-11 21:55:54 +020056import java.util.stream.Collectors;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020057
58import static com.google.common.collect.Lists.newArrayList;
Andrea Campanella0288c872017-08-07 18:32:51 +020059import static org.onosproject.drivers.p4runtime.P4RuntimeFlowRuleProgrammable.Operation.APPLY;
60import static org.onosproject.drivers.p4runtime.P4RuntimeFlowRuleProgrammable.Operation.REMOVE;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020061import static org.onosproject.net.flow.FlowEntry.FlowEntryState.ADDED;
Carmelo Cascone87892e22017-11-13 16:01:29 -080062import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.DELETE;
63import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.INSERT;
64import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.MODIFY;
Frank Wang0e805082017-07-21 14:37:35 +080065
66/**
Carmelo Casconee3a7c742017-09-01 01:25:52 +020067 * Implementation of the flow rule programmable behaviour for P4Runtime.
Frank Wang0e805082017-07-21 14:37:35 +080068 */
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080069public class P4RuntimeFlowRuleProgrammable
70 extends AbstractP4RuntimeHandlerBehaviour
71 implements FlowRuleProgrammable {
Frank Wang0e805082017-07-21 14:37:35 +080072
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080073 // When updating an existing rule, if true, we issue a DELETE operation
74 // before inserting the new one, otherwise we issue a MODIFY operation. This
75 // is useful fore devices that do not support MODIFY operations for table
76 // entries.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080077 private static final String DELETE_BEFORE_UPDATE = "tableDeleteBeforeUpdate";
78 private static final boolean DEFAULT_DELETE_BEFORE_UPDATE = false;
Carmelo Cascone2308e522017-08-25 02:35:12 +020079
Carmelo Cascone81929aa2018-04-07 01:38:55 -070080 // If true, we ignore re-installing rules that already exist in the
81 // device mirror, i.e. same match key and action.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080082 private static final String IGNORE_SAME_ENTRY_UPDATE = "tableIgnoreSameEntryUpdate";
83 private static final boolean DEFAULT_IGNORE_SAME_ENTRY_UPDATE = false;
Carmelo Cascone2308e522017-08-25 02:35:12 +020084
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080085 // If true, we avoid querying the device and return what's already known by
86 // the ONOS store.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080087 private static final String READ_FROM_MIRROR = "tableReadFromMirror";
88 private static final boolean DEFAULT_READ_FROM_MIRROR = false;
Carmelo Casconefe99be92017-09-11 21:55:54 +020089
Carmelo Cascone3da671a2018-02-12 10:43:35 -080090 // If true, we read all direct counters of a table with one request.
91 // Otherwise, we send as many requests as the number of table entries.
92 private static final String READ_ALL_DIRECT_COUNTERS = "tableReadAllDirectCounters";
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080093 // FIXME: set to true as soon as the feature is implemented in P4Runtime.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080094 private static final boolean DEFAULT_READ_ALL_DIRECT_COUNTERS = false;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020095
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +053096 private static final int TABLE_ENTRY_LOCK_EXPIRE_TIME_IN_MIN = 10;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020097
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +053098 // Needed to synchronize operations over the same table entry.
99 private static final LoadingCache<PiTableEntryHandle, Lock>
100 ENTRY_LOCKS = CacheBuilder.newBuilder()
101 .expireAfterAccess(TABLE_ENTRY_LOCK_EXPIRE_TIME_IN_MIN, TimeUnit.MINUTES)
102 .build(new CacheLoader<PiTableEntryHandle, Lock>() {
103 @Override
104 public Lock load(PiTableEntryHandle handle) {
105 return new ReentrantLock();
106 }
107 });
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200108 private PiPipelineModel pipelineModel;
109 private PiPipelineInterpreter interpreter;
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800110 private P4RuntimeTableMirror tableMirror;
111 private PiFlowRuleTranslator translator;
Frank Wang0e805082017-07-21 14:37:35 +0800112
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200113 @Override
114 protected boolean setupBehaviour() {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200115
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200116 if (!super.setupBehaviour()) {
Frank Wang0e805082017-07-21 14:37:35 +0800117 return false;
118 }
119
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200120 if (!device.is(PiPipelineInterpreter.class)) {
121 log.warn("Unable to get interpreter of {}", deviceId);
Frank Wang0e805082017-07-21 14:37:35 +0800122 return false;
123 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200124 interpreter = device.as(PiPipelineInterpreter.class);
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200125 pipelineModel = pipeconf.pipelineModel();
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800126 tableMirror = handler().get(P4RuntimeTableMirror.class);
127 translator = piTranslationService.flowRuleTranslator();
Frank Wang0e805082017-07-21 14:37:35 +0800128 return true;
129 }
130
131 @Override
132 public Collection<FlowEntry> getFlowEntries() {
133
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200134 if (!setupBehaviour()) {
Frank Wang0e805082017-07-21 14:37:35 +0800135 return Collections.emptyList();
136 }
137
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800138 if (driverBoolProperty(READ_FROM_MIRROR, DEFAULT_READ_FROM_MIRROR)) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800139 return getFlowEntriesFromMirror();
Carmelo Casconefe99be92017-09-11 21:55:54 +0200140 }
141
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800142 final ImmutableList.Builder<FlowEntry> result = ImmutableList.builder();
143 final List<PiTableEntry> inconsistentEntries = Lists.newArrayList();
Frank Wang0e805082017-07-21 14:37:35 +0800144
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200145 for (PiTableModel tableModel : pipelineModel.tables()) {
146
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800147 final PiTableId piTableId = tableModel.id();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200148
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800149 // Read table entries.
150 final Collection<PiTableEntry> installedEntries;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200151 try {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800152 // TODO: optimize by dumping entries and counters in parallel
153 // From ALL tables with the same request.
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200154 installedEntries = client.dumpTable(piTableId, pipeconf).get();
155 } catch (InterruptedException | ExecutionException e) {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200156 if (!(e.getCause() instanceof StatusRuntimeException)) {
157 // gRPC errors are logged in the client.
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800158 log.error("Exception while dumping table {} of {}",
159 piTableId, deviceId, e);
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200160 }
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800161 continue; // next table
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200162 }
163
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800164 if (installedEntries.size() == 0) {
165 continue; // next table
166 }
167
168 // Read table direct counters (if any).
169 final Map<PiTableEntry, PiCounterCellData> counterCellMap;
170 if (interpreter.mapTableCounter(piTableId).isPresent()) {
171 PiCounterId piCounterId = interpreter.mapTableCounter(piTableId).get();
172 counterCellMap = readEntryCounters(piCounterId, installedEntries);
173 } else {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200174 counterCellMap = Collections.emptyMap();
175 }
176
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800177 // Forge flow entries with counter values.
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200178 for (PiTableEntry installedEntry : installedEntries) {
179
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800180 final FlowEntry flowEntry = forgeFlowEntry(
181 installedEntry, counterCellMap.get(installedEntry));
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200182
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800183 if (flowEntry == null) {
184 // Entry is on device but unknown to translation service or
185 // device mirror. Inconsistent. Mark for removal.
186 // TODO: make this behaviour configurable
187 // In some cases it's fine for the device to have rules
188 // that were not installed by us.
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200189 inconsistentEntries.add(installedEntry);
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800190 } else {
191 result.add(flowEntry);
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200192 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200193 }
194 }
195
196 if (inconsistentEntries.size() > 0) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800197 // Async clean up inconsistent entries.
198 SharedExecutors.getSingleThreadExecutor().execute(
199 () -> cleanUpInconsistentEntries(inconsistentEntries));
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200200 }
201
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800202 return result.build();
Frank Wang0e805082017-07-21 14:37:35 +0800203 }
204
205 @Override
206 public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200207 return processFlowRules(rules, APPLY);
Frank Wang0e805082017-07-21 14:37:35 +0800208 }
209
210 @Override
211 public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200212 return processFlowRules(rules, REMOVE);
Frank Wang0e805082017-07-21 14:37:35 +0800213 }
214
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800215 private FlowEntry forgeFlowEntry(PiTableEntry entry,
216 PiCounterCellData cellData) {
217 final PiTableEntryHandle handle = PiTableEntryHandle
218 .of(deviceId, entry);
219 final Optional<PiTranslatedEntity<FlowRule, PiTableEntry>>
220 translatedEntity = translator.lookup(handle);
221 final TimedEntry<PiTableEntry> timedEntry = tableMirror.get(handle);
222
223 if (!translatedEntity.isPresent()) {
224 log.debug("Handle not found in store: {}", handle);
225 return null;
226 }
227
228 if (timedEntry == null) {
229 log.debug("Handle not found in device mirror: {}", handle);
230 return null;
231 }
232
233 if (cellData != null) {
234 return new DefaultFlowEntry(translatedEntity.get().original(),
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700235 ADDED, timedEntry.lifeSec(), cellData.packets(),
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800236 cellData.bytes());
237 } else {
238 return new DefaultFlowEntry(translatedEntity.get().original(),
239 ADDED, timedEntry.lifeSec(), 0, 0);
240 }
241 }
242
243 private Collection<FlowEntry> getFlowEntriesFromMirror() {
244 return tableMirror.getAll(deviceId).stream()
245 .map(timedEntry -> forgeFlowEntry(
246 timedEntry.entry(), null))
247 .collect(Collectors.toList());
248 }
249
250 private void cleanUpInconsistentEntries(Collection<PiTableEntry> piEntries) {
251 log.warn("Found {} entries from {} not on translation store, removing them...",
252 piEntries.size(), deviceId);
253 piEntries.forEach(entry -> {
254 log.debug(entry.toString());
255 applyEntry(PiTableEntryHandle.of(deviceId, entry),
256 entry, null, REMOVE);
257 });
258 }
259
260 private Collection<FlowRule> processFlowRules(Collection<FlowRule> rules,
261 Operation driverOperation) {
Frank Wang0e805082017-07-21 14:37:35 +0800262
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200263 if (!setupBehaviour()) {
Frank Wang0e805082017-07-21 14:37:35 +0800264 return Collections.emptyList();
265 }
266
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800267 final ImmutableList.Builder<FlowRule> result = ImmutableList.builder();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200268
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800269 // TODO: send writes in bulk (e.g. all entries to insert, modify or delete).
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200270 // Instead of calling the client for each one of them.
271
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800272 for (FlowRule ruleToApply : rules) {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200273
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800274 final PiTableEntry piEntryToApply;
Frank Wang0e805082017-07-21 14:37:35 +0800275 try {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800276 piEntryToApply = translator.translate(ruleToApply, pipeconf);
Carmelo Cascone326ad2d2017-11-28 18:09:13 -0800277 } catch (PiTranslationException e) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800278 log.warn("Unable to translate flow rule for pipeconf '{}': {} - {}",
279 pipeconf.id(), e.getMessage(), ruleToApply);
280 // Next rule.
281 continue;
Frank Wang0e805082017-07-21 14:37:35 +0800282 }
Frank Wang0e805082017-07-21 14:37:35 +0800283
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800284 final PiTableEntryHandle handle = PiTableEntryHandle
285 .of(deviceId, piEntryToApply);
Frank Wang0e805082017-07-21 14:37:35 +0800286
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800287 // Serialize operations over the same match key/table/device ID.
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +0530288 ENTRY_LOCKS.getUnchecked(handle).lock();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200289 try {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800290 if (applyEntry(handle, piEntryToApply,
291 ruleToApply, driverOperation)) {
292 result.add(ruleToApply);
Frank Wang0e805082017-07-21 14:37:35 +0800293 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200294 } finally {
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +0530295 ENTRY_LOCKS.getUnchecked(handle).unlock();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200296 }
297 }
298
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800299 return result.build();
300 }
301
302 /**
303 * Applies the given entry to the device, and returns true if the operation
304 * was successful, false otherwise.
305 */
306 private boolean applyEntry(PiTableEntryHandle handle,
307 PiTableEntry piEntryToApply,
308 FlowRule ruleToApply,
309 Operation driverOperation) {
310 // Depending on the driver operation, and if a matching rule exists on
311 // the device, decide which P4 Runtime write operation to perform for
312 // this entry.
313 final TimedEntry<PiTableEntry> piEntryOnDevice = tableMirror.get(handle);
314 final WriteOperationType p4Operation;
315 if (driverOperation == APPLY) {
316 if (piEntryOnDevice == null) {
317 // Entry is first-timer.
318 p4Operation = INSERT;
319 } else {
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800320 if (driverBoolProperty(IGNORE_SAME_ENTRY_UPDATE,
321 DEFAULT_IGNORE_SAME_ENTRY_UPDATE)
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800322 && piEntryToApply.action().equals(piEntryOnDevice.entry().action())) {
323 log.debug("Ignoring re-apply of existing entry: {}", piEntryToApply);
324 p4Operation = null;
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800325 } else if (driverBoolProperty(DELETE_BEFORE_UPDATE,
326 DEFAULT_DELETE_BEFORE_UPDATE)) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800327 // Some devices return error when updating existing
328 // entries. If requested, remove entry before
329 // re-inserting the modified one.
330 applyEntry(handle, piEntryOnDevice.entry(), null, REMOVE);
331 p4Operation = INSERT;
332 } else {
333 p4Operation = MODIFY;
334 }
335 }
336 } else {
337 p4Operation = DELETE;
338 }
339
340 if (p4Operation != null) {
341 if (writeEntry(piEntryToApply, p4Operation)) {
342 updateStores(handle, piEntryToApply, ruleToApply, p4Operation);
343 return true;
344 } else {
345 return false;
346 }
347 } else {
348 // If no operation, let's pretend we applied the rule to the device.
349 return true;
350 }
351 }
352
353 /**
354 * Performs a write operation on the device.
355 */
356 private boolean writeEntry(PiTableEntry entry,
357 WriteOperationType p4Operation) {
358 try {
359 if (client.writeTableEntries(
360 newArrayList(entry), p4Operation, pipeconf).get()) {
361 return true;
362 } else {
363 log.warn("Unable to {} table entry in {}: {}",
364 p4Operation.name(), deviceId, entry);
365 }
366 } catch (InterruptedException | ExecutionException e) {
367 log.warn("Exception while performing {} table entry operation:",
368 p4Operation, e);
369 }
370 return false;
371 }
372
373 private void updateStores(PiTableEntryHandle handle,
374 PiTableEntry entry,
375 FlowRule rule,
376 WriteOperationType p4Operation) {
377 switch (p4Operation) {
378 case INSERT:
379 case MODIFY:
380 tableMirror.put(handle, entry);
381 translator.learn(handle, new PiTranslatedEntity<>(rule, entry, handle));
382 break;
383 case DELETE:
384 tableMirror.remove(handle);
385 translator.forget(handle);
386 break;
387 default:
388 throw new IllegalArgumentException(
389 "Unknown operation " + p4Operation.name());
390 }
391 }
392
393 private Map<PiTableEntry, PiCounterCellData> readEntryCounters(
394 PiCounterId counterId, Collection<PiTableEntry> tableEntries) {
395 Collection<PiCounterCellData> cellDatas;
396 try {
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800397 if (driverBoolProperty(READ_ALL_DIRECT_COUNTERS,
398 DEFAULT_READ_ALL_DIRECT_COUNTERS)) {
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700399 // FIXME: re-implement reading all counters ONOS-7595, or
400 // (even better) read counters when dumping table entries ONOS-7596
401 // cellDatas = client.readAllCounterCells(
402 // singleton(counterId), pipeconf).get();
403 cellDatas = Collections.emptyList();
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800404 } else {
405 Set<PiCounterCellId> cellIds = tableEntries.stream()
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700406 .map(PiCounterCellId::ofDirect)
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800407 .collect(Collectors.toSet());
408 cellDatas = client.readCounterCells(cellIds, pipeconf).get();
409 }
410 return cellDatas.stream()
411 .collect(Collectors.toMap(c -> c.cellId().tableEntry(), c -> c));
412 } catch (InterruptedException | ExecutionException e) {
413 if (!(e.getCause() instanceof StatusRuntimeException)) {
414 // gRPC errors are logged in the client.
415 log.error("Exception while reading counter '{}' from {}: {}",
416 counterId, deviceId, e);
417 }
418 return Collections.emptyMap();
419 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200420 }
421
422 enum Operation {
423 APPLY, REMOVE
Frank Wang0e805082017-07-21 14:37:35 +0800424 }
Carmelo Cascone87892e22017-11-13 16:01:29 -0800425}