blob: bcc298d0316af10e248350b3ad4de920cd65b208 [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;
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080059import static java.util.Collections.singleton;
Andrea Campanella0288c872017-08-07 18:32:51 +020060import static org.onosproject.drivers.p4runtime.P4RuntimeFlowRuleProgrammable.Operation.APPLY;
61import static org.onosproject.drivers.p4runtime.P4RuntimeFlowRuleProgrammable.Operation.REMOVE;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020062import static org.onosproject.net.flow.FlowEntry.FlowEntryState.ADDED;
Carmelo Cascone87892e22017-11-13 16:01:29 -080063import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.DELETE;
64import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.INSERT;
65import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.MODIFY;
Frank Wang0e805082017-07-21 14:37:35 +080066
67/**
Carmelo Casconee3a7c742017-09-01 01:25:52 +020068 * Implementation of the flow rule programmable behaviour for P4Runtime.
Frank Wang0e805082017-07-21 14:37:35 +080069 */
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080070public class P4RuntimeFlowRuleProgrammable
71 extends AbstractP4RuntimeHandlerBehaviour
72 implements FlowRuleProgrammable {
Frank Wang0e805082017-07-21 14:37:35 +080073
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080074 // When updating an existing rule, if true, we issue a DELETE operation
75 // before inserting the new one, otherwise we issue a MODIFY operation. This
76 // is useful fore devices that do not support MODIFY operations for table
77 // entries.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080078 private static final String DELETE_BEFORE_UPDATE = "tableDeleteBeforeUpdate";
79 private static final boolean DEFAULT_DELETE_BEFORE_UPDATE = false;
Carmelo Cascone2308e522017-08-25 02:35:12 +020080
Carmelo Cascone3da671a2018-02-12 10:43:35 -080081 // If true, we ignore re-installing rules that already exist the
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080082 // device, i.e. same match key and action.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080083 private static final String IGNORE_SAME_ENTRY_UPDATE = "tableIgnoreSameEntryUpdate";
84 private static final boolean DEFAULT_IGNORE_SAME_ENTRY_UPDATE = false;
Carmelo Cascone2308e522017-08-25 02:35:12 +020085
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080086 // If true, we avoid querying the device and return what's already known by
87 // the ONOS store.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080088 private static final String READ_FROM_MIRROR = "tableReadFromMirror";
89 private static final boolean DEFAULT_READ_FROM_MIRROR = false;
Carmelo Casconefe99be92017-09-11 21:55:54 +020090
Carmelo Cascone3da671a2018-02-12 10:43:35 -080091 // If true, we read all direct counters of a table with one request.
92 // Otherwise, we send as many requests as the number of table entries.
93 private static final String READ_ALL_DIRECT_COUNTERS = "tableReadAllDirectCounters";
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080094 // FIXME: set to true as soon as the feature is implemented in P4Runtime.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080095 private static final boolean DEFAULT_READ_ALL_DIRECT_COUNTERS = false;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020096
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +053097 private static final int TABLE_ENTRY_LOCK_EXPIRE_TIME_IN_MIN = 10;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020098
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +053099 // Needed to synchronize operations over the same table entry.
100 private static final LoadingCache<PiTableEntryHandle, Lock>
101 ENTRY_LOCKS = CacheBuilder.newBuilder()
102 .expireAfterAccess(TABLE_ENTRY_LOCK_EXPIRE_TIME_IN_MIN, TimeUnit.MINUTES)
103 .build(new CacheLoader<PiTableEntryHandle, Lock>() {
104 @Override
105 public Lock load(PiTableEntryHandle handle) {
106 return new ReentrantLock();
107 }
108 });
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200109 private PiPipelineModel pipelineModel;
110 private PiPipelineInterpreter interpreter;
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800111 private P4RuntimeTableMirror tableMirror;
112 private PiFlowRuleTranslator translator;
Frank Wang0e805082017-07-21 14:37:35 +0800113
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200114 @Override
115 protected boolean setupBehaviour() {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200116
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200117 if (!super.setupBehaviour()) {
Frank Wang0e805082017-07-21 14:37:35 +0800118 return false;
119 }
120
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200121 if (!device.is(PiPipelineInterpreter.class)) {
122 log.warn("Unable to get interpreter of {}", deviceId);
Frank Wang0e805082017-07-21 14:37:35 +0800123 return false;
124 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200125 interpreter = device.as(PiPipelineInterpreter.class);
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200126 pipelineModel = pipeconf.pipelineModel();
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800127 tableMirror = handler().get(P4RuntimeTableMirror.class);
128 translator = piTranslationService.flowRuleTranslator();
Frank Wang0e805082017-07-21 14:37:35 +0800129 return true;
130 }
131
132 @Override
133 public Collection<FlowEntry> getFlowEntries() {
134
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200135 if (!setupBehaviour()) {
Frank Wang0e805082017-07-21 14:37:35 +0800136 return Collections.emptyList();
137 }
138
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800139 if (driverBoolProperty(READ_FROM_MIRROR, DEFAULT_READ_FROM_MIRROR)) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800140 return getFlowEntriesFromMirror();
Carmelo Casconefe99be92017-09-11 21:55:54 +0200141 }
142
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800143 final ImmutableList.Builder<FlowEntry> result = ImmutableList.builder();
144 final List<PiTableEntry> inconsistentEntries = Lists.newArrayList();
Frank Wang0e805082017-07-21 14:37:35 +0800145
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200146 for (PiTableModel tableModel : pipelineModel.tables()) {
147
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800148 final PiTableId piTableId = tableModel.id();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200149
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800150 // Read table entries.
151 final Collection<PiTableEntry> installedEntries;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200152 try {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800153 // TODO: optimize by dumping entries and counters in parallel
154 // From ALL tables with the same request.
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200155 installedEntries = client.dumpTable(piTableId, pipeconf).get();
156 } catch (InterruptedException | ExecutionException e) {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200157 if (!(e.getCause() instanceof StatusRuntimeException)) {
158 // gRPC errors are logged in the client.
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800159 log.error("Exception while dumping table {} of {}",
160 piTableId, deviceId, e);
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200161 }
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800162 continue; // next table
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200163 }
164
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800165 if (installedEntries.size() == 0) {
166 continue; // next table
167 }
168
169 // Read table direct counters (if any).
170 final Map<PiTableEntry, PiCounterCellData> counterCellMap;
171 if (interpreter.mapTableCounter(piTableId).isPresent()) {
172 PiCounterId piCounterId = interpreter.mapTableCounter(piTableId).get();
173 counterCellMap = readEntryCounters(piCounterId, installedEntries);
174 } else {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200175 counterCellMap = Collections.emptyMap();
176 }
177
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800178 // Forge flow entries with counter values.
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200179 for (PiTableEntry installedEntry : installedEntries) {
180
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800181 final FlowEntry flowEntry = forgeFlowEntry(
182 installedEntry, counterCellMap.get(installedEntry));
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200183
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800184 if (flowEntry == null) {
185 // Entry is on device but unknown to translation service or
186 // device mirror. Inconsistent. Mark for removal.
187 // TODO: make this behaviour configurable
188 // In some cases it's fine for the device to have rules
189 // that were not installed by us.
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200190 inconsistentEntries.add(installedEntry);
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800191 } else {
192 result.add(flowEntry);
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200193 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200194 }
195 }
196
197 if (inconsistentEntries.size() > 0) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800198 // Async clean up inconsistent entries.
199 SharedExecutors.getSingleThreadExecutor().execute(
200 () -> cleanUpInconsistentEntries(inconsistentEntries));
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200201 }
202
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800203 return result.build();
Frank Wang0e805082017-07-21 14:37:35 +0800204 }
205
206 @Override
207 public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200208 return processFlowRules(rules, APPLY);
Frank Wang0e805082017-07-21 14:37:35 +0800209 }
210
211 @Override
212 public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200213 return processFlowRules(rules, REMOVE);
Frank Wang0e805082017-07-21 14:37:35 +0800214 }
215
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800216 private FlowEntry forgeFlowEntry(PiTableEntry entry,
217 PiCounterCellData cellData) {
218 final PiTableEntryHandle handle = PiTableEntryHandle
219 .of(deviceId, entry);
220 final Optional<PiTranslatedEntity<FlowRule, PiTableEntry>>
221 translatedEntity = translator.lookup(handle);
222 final TimedEntry<PiTableEntry> timedEntry = tableMirror.get(handle);
223
224 if (!translatedEntity.isPresent()) {
225 log.debug("Handle not found in store: {}", handle);
226 return null;
227 }
228
229 if (timedEntry == null) {
230 log.debug("Handle not found in device mirror: {}", handle);
231 return null;
232 }
233
234 if (cellData != null) {
235 return new DefaultFlowEntry(translatedEntity.get().original(),
236 ADDED, timedEntry.lifeSec(), cellData.bytes(),
237 cellData.bytes());
238 } else {
239 return new DefaultFlowEntry(translatedEntity.get().original(),
240 ADDED, timedEntry.lifeSec(), 0, 0);
241 }
242 }
243
244 private Collection<FlowEntry> getFlowEntriesFromMirror() {
245 return tableMirror.getAll(deviceId).stream()
246 .map(timedEntry -> forgeFlowEntry(
247 timedEntry.entry(), null))
248 .collect(Collectors.toList());
249 }
250
251 private void cleanUpInconsistentEntries(Collection<PiTableEntry> piEntries) {
252 log.warn("Found {} entries from {} not on translation store, removing them...",
253 piEntries.size(), deviceId);
254 piEntries.forEach(entry -> {
255 log.debug(entry.toString());
256 applyEntry(PiTableEntryHandle.of(deviceId, entry),
257 entry, null, REMOVE);
258 });
259 }
260
261 private Collection<FlowRule> processFlowRules(Collection<FlowRule> rules,
262 Operation driverOperation) {
Frank Wang0e805082017-07-21 14:37:35 +0800263
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200264 if (!setupBehaviour()) {
Frank Wang0e805082017-07-21 14:37:35 +0800265 return Collections.emptyList();
266 }
267
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800268 final ImmutableList.Builder<FlowRule> result = ImmutableList.builder();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200269
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800270 // TODO: send writes in bulk (e.g. all entries to insert, modify or delete).
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200271 // Instead of calling the client for each one of them.
272
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800273 for (FlowRule ruleToApply : rules) {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200274
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800275 final PiTableEntry piEntryToApply;
Frank Wang0e805082017-07-21 14:37:35 +0800276 try {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800277 piEntryToApply = translator.translate(ruleToApply, pipeconf);
Carmelo Cascone326ad2d2017-11-28 18:09:13 -0800278 } catch (PiTranslationException e) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800279 log.warn("Unable to translate flow rule for pipeconf '{}': {} - {}",
280 pipeconf.id(), e.getMessage(), ruleToApply);
281 // Next rule.
282 continue;
Frank Wang0e805082017-07-21 14:37:35 +0800283 }
Frank Wang0e805082017-07-21 14:37:35 +0800284
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800285 final PiTableEntryHandle handle = PiTableEntryHandle
286 .of(deviceId, piEntryToApply);
Frank Wang0e805082017-07-21 14:37:35 +0800287
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800288 // Serialize operations over the same match key/table/device ID.
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +0530289 ENTRY_LOCKS.getUnchecked(handle).lock();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200290 try {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800291 if (applyEntry(handle, piEntryToApply,
292 ruleToApply, driverOperation)) {
293 result.add(ruleToApply);
Frank Wang0e805082017-07-21 14:37:35 +0800294 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200295 } finally {
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +0530296 ENTRY_LOCKS.getUnchecked(handle).unlock();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200297 }
298 }
299
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800300 return result.build();
301 }
302
303 /**
304 * Applies the given entry to the device, and returns true if the operation
305 * was successful, false otherwise.
306 */
307 private boolean applyEntry(PiTableEntryHandle handle,
308 PiTableEntry piEntryToApply,
309 FlowRule ruleToApply,
310 Operation driverOperation) {
311 // Depending on the driver operation, and if a matching rule exists on
312 // the device, decide which P4 Runtime write operation to perform for
313 // this entry.
314 final TimedEntry<PiTableEntry> piEntryOnDevice = tableMirror.get(handle);
315 final WriteOperationType p4Operation;
316 if (driverOperation == APPLY) {
317 if (piEntryOnDevice == null) {
318 // Entry is first-timer.
319 p4Operation = INSERT;
320 } else {
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800321 if (driverBoolProperty(IGNORE_SAME_ENTRY_UPDATE,
322 DEFAULT_IGNORE_SAME_ENTRY_UPDATE)
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800323 && piEntryToApply.action().equals(piEntryOnDevice.entry().action())) {
324 log.debug("Ignoring re-apply of existing entry: {}", piEntryToApply);
325 p4Operation = null;
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800326 } else if (driverBoolProperty(DELETE_BEFORE_UPDATE,
327 DEFAULT_DELETE_BEFORE_UPDATE)) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800328 // Some devices return error when updating existing
329 // entries. If requested, remove entry before
330 // re-inserting the modified one.
331 applyEntry(handle, piEntryOnDevice.entry(), null, REMOVE);
332 p4Operation = INSERT;
333 } else {
334 p4Operation = MODIFY;
335 }
336 }
337 } else {
338 p4Operation = DELETE;
339 }
340
341 if (p4Operation != null) {
342 if (writeEntry(piEntryToApply, p4Operation)) {
343 updateStores(handle, piEntryToApply, ruleToApply, p4Operation);
344 return true;
345 } else {
346 return false;
347 }
348 } else {
349 // If no operation, let's pretend we applied the rule to the device.
350 return true;
351 }
352 }
353
354 /**
355 * Performs a write operation on the device.
356 */
357 private boolean writeEntry(PiTableEntry entry,
358 WriteOperationType p4Operation) {
359 try {
360 if (client.writeTableEntries(
361 newArrayList(entry), p4Operation, pipeconf).get()) {
362 return true;
363 } else {
364 log.warn("Unable to {} table entry in {}: {}",
365 p4Operation.name(), deviceId, entry);
366 }
367 } catch (InterruptedException | ExecutionException e) {
368 log.warn("Exception while performing {} table entry operation:",
369 p4Operation, e);
370 }
371 return false;
372 }
373
374 private void updateStores(PiTableEntryHandle handle,
375 PiTableEntry entry,
376 FlowRule rule,
377 WriteOperationType p4Operation) {
378 switch (p4Operation) {
379 case INSERT:
380 case MODIFY:
381 tableMirror.put(handle, entry);
382 translator.learn(handle, new PiTranslatedEntity<>(rule, entry, handle));
383 break;
384 case DELETE:
385 tableMirror.remove(handle);
386 translator.forget(handle);
387 break;
388 default:
389 throw new IllegalArgumentException(
390 "Unknown operation " + p4Operation.name());
391 }
392 }
393
394 private Map<PiTableEntry, PiCounterCellData> readEntryCounters(
395 PiCounterId counterId, Collection<PiTableEntry> tableEntries) {
396 Collection<PiCounterCellData> cellDatas;
397 try {
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800398 if (driverBoolProperty(READ_ALL_DIRECT_COUNTERS,
399 DEFAULT_READ_ALL_DIRECT_COUNTERS)) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800400 cellDatas = client.readAllCounterCells(
401 singleton(counterId), pipeconf).get();
402 } else {
403 Set<PiCounterCellId> cellIds = tableEntries.stream()
404 .map(entry -> PiCounterCellId.ofDirect(counterId, entry))
405 .collect(Collectors.toSet());
406 cellDatas = client.readCounterCells(cellIds, pipeconf).get();
407 }
408 return cellDatas.stream()
409 .collect(Collectors.toMap(c -> c.cellId().tableEntry(), c -> c));
410 } catch (InterruptedException | ExecutionException e) {
411 if (!(e.getCause() instanceof StatusRuntimeException)) {
412 // gRPC errors are logged in the client.
413 log.error("Exception while reading counter '{}' from {}: {}",
414 counterId, deviceId, e);
415 }
416 return Collections.emptyMap();
417 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200418 }
419
420 enum Operation {
421 APPLY, REMOVE
Frank Wang0e805082017-07-21 14:37:35 +0800422 }
Carmelo Cascone87892e22017-11-13 16:01:29 -0800423}