blob: 00fe938030692415461d2ab1987c45573471825f [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;
Frank Wang0e805082017-07-21 14:37:35 +080032import org.onosproject.net.pi.model.PiPipelineInterpreter;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020033import org.onosproject.net.pi.model.PiPipelineModel;
Carmelo Cascone87892e22017-11-13 16:01:29 -080034import org.onosproject.net.pi.model.PiTableId;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020035import org.onosproject.net.pi.model.PiTableModel;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020036import org.onosproject.net.pi.runtime.PiCounterCellData;
37import org.onosproject.net.pi.runtime.PiCounterCellId;
Frank Wang0e805082017-07-21 14:37:35 +080038import org.onosproject.net.pi.runtime.PiTableEntry;
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080039import org.onosproject.net.pi.runtime.PiTableEntryHandle;
40import org.onosproject.net.pi.service.PiFlowRuleTranslator;
41import org.onosproject.net.pi.service.PiTranslatedEntity;
Carmelo Cascone326ad2d2017-11-28 18:09:13 -080042import org.onosproject.net.pi.service.PiTranslationException;
Frank Wang0e805082017-07-21 14:37:35 +080043import org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType;
Frank Wang0e805082017-07-21 14:37:35 +080044
45import java.util.Collection;
46import java.util.Collections;
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +053047import java.util.List;
Carmelo Cascone3da671a2018-02-12 10:43:35 -080048import java.util.Map;
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080049import java.util.Optional;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020050import java.util.Set;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020051import java.util.concurrent.ExecutionException;
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +053052import java.util.concurrent.TimeUnit;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020053import java.util.concurrent.locks.Lock;
54import java.util.concurrent.locks.ReentrantLock;
Carmelo Casconefe99be92017-09-11 21:55:54 +020055import java.util.stream.Collectors;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020056
57import static com.google.common.collect.Lists.newArrayList;
Andrea Campanella0288c872017-08-07 18:32:51 +020058import static org.onosproject.drivers.p4runtime.P4RuntimeFlowRuleProgrammable.Operation.APPLY;
59import static org.onosproject.drivers.p4runtime.P4RuntimeFlowRuleProgrammable.Operation.REMOVE;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +020060import static org.onosproject.net.flow.FlowEntry.FlowEntryState.ADDED;
Carmelo Cascone87892e22017-11-13 16:01:29 -080061import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.DELETE;
62import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.INSERT;
63import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.MODIFY;
Frank Wang0e805082017-07-21 14:37:35 +080064
65/**
Carmelo Casconee3a7c742017-09-01 01:25:52 +020066 * Implementation of the flow rule programmable behaviour for P4Runtime.
Frank Wang0e805082017-07-21 14:37:35 +080067 */
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080068public class P4RuntimeFlowRuleProgrammable
69 extends AbstractP4RuntimeHandlerBehaviour
70 implements FlowRuleProgrammable {
Frank Wang0e805082017-07-21 14:37:35 +080071
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080072 // When updating an existing rule, if true, we issue a DELETE operation
73 // before inserting the new one, otherwise we issue a MODIFY operation. This
74 // is useful fore devices that do not support MODIFY operations for table
75 // entries.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080076 private static final String DELETE_BEFORE_UPDATE = "tableDeleteBeforeUpdate";
77 private static final boolean DEFAULT_DELETE_BEFORE_UPDATE = false;
Carmelo Cascone2308e522017-08-25 02:35:12 +020078
Carmelo Cascone81929aa2018-04-07 01:38:55 -070079 // If true, we ignore re-installing rules that already exist in the
80 // device mirror, i.e. same match key and action.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080081 private static final String IGNORE_SAME_ENTRY_UPDATE = "tableIgnoreSameEntryUpdate";
82 private static final boolean DEFAULT_IGNORE_SAME_ENTRY_UPDATE = false;
Carmelo Cascone2308e522017-08-25 02:35:12 +020083
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080084 // If true, we avoid querying the device and return what's already known by
85 // the ONOS store.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080086 private static final String READ_FROM_MIRROR = "tableReadFromMirror";
87 private static final boolean DEFAULT_READ_FROM_MIRROR = false;
Carmelo Casconefe99be92017-09-11 21:55:54 +020088
Carmelo Cascone255125d2018-04-11 14:03:22 -070089 // If true, we read counters when reading table entries (if table has
90 // counters). Otherwise, we don't.
91 private static final String SUPPORT_TABLE_COUNTERS = "supportTableCounters";
92 private static final boolean DEFAULT_SUPPORT_TABLE_COUNTERS = true;
93
Carmelo Cascone3da671a2018-02-12 10:43:35 -080094 // If true, we read all direct counters of a table with one request.
95 // Otherwise, we send as many requests as the number of table entries.
96 private static final String READ_ALL_DIRECT_COUNTERS = "tableReadAllDirectCounters";
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -080097 // FIXME: set to true as soon as the feature is implemented in P4Runtime.
Carmelo Cascone3da671a2018-02-12 10:43:35 -080098 private static final boolean DEFAULT_READ_ALL_DIRECT_COUNTERS = false;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020099
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +0530100 private static final int TABLE_ENTRY_LOCK_EXPIRE_TIME_IN_MIN = 10;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200101
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +0530102 // Needed to synchronize operations over the same table entry.
103 private static final LoadingCache<PiTableEntryHandle, Lock>
104 ENTRY_LOCKS = CacheBuilder.newBuilder()
105 .expireAfterAccess(TABLE_ENTRY_LOCK_EXPIRE_TIME_IN_MIN, TimeUnit.MINUTES)
106 .build(new CacheLoader<PiTableEntryHandle, Lock>() {
107 @Override
108 public Lock load(PiTableEntryHandle handle) {
109 return new ReentrantLock();
110 }
111 });
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200112 private PiPipelineModel pipelineModel;
113 private PiPipelineInterpreter interpreter;
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800114 private P4RuntimeTableMirror tableMirror;
115 private PiFlowRuleTranslator translator;
Frank Wang0e805082017-07-21 14:37:35 +0800116
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200117 @Override
118 protected boolean setupBehaviour() {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200119
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200120 if (!super.setupBehaviour()) {
Frank Wang0e805082017-07-21 14:37:35 +0800121 return false;
122 }
123
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200124 if (!device.is(PiPipelineInterpreter.class)) {
125 log.warn("Unable to get interpreter of {}", deviceId);
Frank Wang0e805082017-07-21 14:37:35 +0800126 return false;
127 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200128 interpreter = device.as(PiPipelineInterpreter.class);
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200129 pipelineModel = pipeconf.pipelineModel();
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800130 tableMirror = handler().get(P4RuntimeTableMirror.class);
131 translator = piTranslationService.flowRuleTranslator();
Frank Wang0e805082017-07-21 14:37:35 +0800132 return true;
133 }
134
135 @Override
136 public Collection<FlowEntry> getFlowEntries() {
137
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200138 if (!setupBehaviour()) {
Frank Wang0e805082017-07-21 14:37:35 +0800139 return Collections.emptyList();
140 }
141
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800142 if (driverBoolProperty(READ_FROM_MIRROR, DEFAULT_READ_FROM_MIRROR)) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800143 return getFlowEntriesFromMirror();
Carmelo Casconefe99be92017-09-11 21:55:54 +0200144 }
145
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800146 final ImmutableList.Builder<FlowEntry> result = ImmutableList.builder();
147 final List<PiTableEntry> inconsistentEntries = Lists.newArrayList();
Frank Wang0e805082017-07-21 14:37:35 +0800148
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200149 for (PiTableModel tableModel : pipelineModel.tables()) {
150
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800151 final PiTableId piTableId = tableModel.id();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200152
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800153 // Read table entries.
154 final Collection<PiTableEntry> installedEntries;
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200155 try {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800156 // TODO: optimize by dumping entries and counters in parallel
157 // From ALL tables with the same request.
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200158 installedEntries = client.dumpTable(piTableId, pipeconf).get();
159 } catch (InterruptedException | ExecutionException e) {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200160 if (!(e.getCause() instanceof StatusRuntimeException)) {
161 // gRPC errors are logged in the client.
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800162 log.error("Exception while dumping table {} of {}",
163 piTableId, deviceId, e);
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200164 }
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800165 continue; // next table
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200166 }
167
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800168 if (installedEntries.size() == 0) {
169 continue; // next table
170 }
171
172 // Read table direct counters (if any).
Carmelo Cascone255125d2018-04-11 14:03:22 -0700173 final Map<PiTableEntry, PiCounterCellData> counterCellMap =
174 readEntryCounters(installedEntries);
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200175
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800176 // Forge flow entries with counter values.
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200177 for (PiTableEntry installedEntry : installedEntries) {
178
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800179 final FlowEntry flowEntry = forgeFlowEntry(
180 installedEntry, counterCellMap.get(installedEntry));
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200181
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800182 if (flowEntry == null) {
183 // Entry is on device but unknown to translation service or
184 // device mirror. Inconsistent. Mark for removal.
185 // TODO: make this behaviour configurable
186 // In some cases it's fine for the device to have rules
187 // that were not installed by us.
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200188 inconsistentEntries.add(installedEntry);
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800189 } else {
190 result.add(flowEntry);
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200191 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200192 }
193 }
194
195 if (inconsistentEntries.size() > 0) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800196 // Async clean up inconsistent entries.
197 SharedExecutors.getSingleThreadExecutor().execute(
198 () -> cleanUpInconsistentEntries(inconsistentEntries));
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200199 }
200
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800201 return result.build();
Frank Wang0e805082017-07-21 14:37:35 +0800202 }
203
204 @Override
205 public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200206 return processFlowRules(rules, APPLY);
Frank Wang0e805082017-07-21 14:37:35 +0800207 }
208
209 @Override
210 public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200211 return processFlowRules(rules, REMOVE);
Frank Wang0e805082017-07-21 14:37:35 +0800212 }
213
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800214 private FlowEntry forgeFlowEntry(PiTableEntry entry,
215 PiCounterCellData cellData) {
216 final PiTableEntryHandle handle = PiTableEntryHandle
217 .of(deviceId, entry);
218 final Optional<PiTranslatedEntity<FlowRule, PiTableEntry>>
219 translatedEntity = translator.lookup(handle);
220 final TimedEntry<PiTableEntry> timedEntry = tableMirror.get(handle);
221
222 if (!translatedEntity.isPresent()) {
223 log.debug("Handle not found in store: {}", handle);
224 return null;
225 }
226
227 if (timedEntry == null) {
228 log.debug("Handle not found in device mirror: {}", handle);
229 return null;
230 }
231
232 if (cellData != null) {
233 return new DefaultFlowEntry(translatedEntity.get().original(),
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700234 ADDED, timedEntry.lifeSec(), cellData.packets(),
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800235 cellData.bytes());
236 } else {
237 return new DefaultFlowEntry(translatedEntity.get().original(),
238 ADDED, timedEntry.lifeSec(), 0, 0);
239 }
240 }
241
242 private Collection<FlowEntry> getFlowEntriesFromMirror() {
243 return tableMirror.getAll(deviceId).stream()
244 .map(timedEntry -> forgeFlowEntry(
245 timedEntry.entry(), null))
246 .collect(Collectors.toList());
247 }
248
249 private void cleanUpInconsistentEntries(Collection<PiTableEntry> piEntries) {
250 log.warn("Found {} entries from {} not on translation store, removing them...",
251 piEntries.size(), deviceId);
252 piEntries.forEach(entry -> {
253 log.debug(entry.toString());
254 applyEntry(PiTableEntryHandle.of(deviceId, entry),
255 entry, null, REMOVE);
256 });
257 }
258
259 private Collection<FlowRule> processFlowRules(Collection<FlowRule> rules,
260 Operation driverOperation) {
Frank Wang0e805082017-07-21 14:37:35 +0800261
Carmelo Casconee3a7c742017-09-01 01:25:52 +0200262 if (!setupBehaviour()) {
Frank Wang0e805082017-07-21 14:37:35 +0800263 return Collections.emptyList();
264 }
265
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800266 final ImmutableList.Builder<FlowRule> result = ImmutableList.builder();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200267
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800268 // TODO: send writes in bulk (e.g. all entries to insert, modify or delete).
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200269 // Instead of calling the client for each one of them.
270
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800271 for (FlowRule ruleToApply : rules) {
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200272
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800273 final PiTableEntry piEntryToApply;
Frank Wang0e805082017-07-21 14:37:35 +0800274 try {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800275 piEntryToApply = translator.translate(ruleToApply, pipeconf);
Carmelo Cascone326ad2d2017-11-28 18:09:13 -0800276 } catch (PiTranslationException e) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800277 log.warn("Unable to translate flow rule for pipeconf '{}': {} - {}",
278 pipeconf.id(), e.getMessage(), ruleToApply);
279 // Next rule.
280 continue;
Frank Wang0e805082017-07-21 14:37:35 +0800281 }
Frank Wang0e805082017-07-21 14:37:35 +0800282
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800283 final PiTableEntryHandle handle = PiTableEntryHandle
284 .of(deviceId, piEntryToApply);
Frank Wang0e805082017-07-21 14:37:35 +0800285
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800286 // Serialize operations over the same match key/table/device ID.
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +0530287 ENTRY_LOCKS.getUnchecked(handle).lock();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200288 try {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800289 if (applyEntry(handle, piEntryToApply,
290 ruleToApply, driverOperation)) {
291 result.add(ruleToApply);
Frank Wang0e805082017-07-21 14:37:35 +0800292 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200293 } finally {
Manjunath Vanaraj59ad6572017-12-26 11:10:57 +0530294 ENTRY_LOCKS.getUnchecked(handle).unlock();
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200295 }
296 }
297
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800298 return result.build();
299 }
300
301 /**
302 * Applies the given entry to the device, and returns true if the operation
303 * was successful, false otherwise.
304 */
305 private boolean applyEntry(PiTableEntryHandle handle,
306 PiTableEntry piEntryToApply,
307 FlowRule ruleToApply,
308 Operation driverOperation) {
309 // Depending on the driver operation, and if a matching rule exists on
310 // the device, decide which P4 Runtime write operation to perform for
311 // this entry.
312 final TimedEntry<PiTableEntry> piEntryOnDevice = tableMirror.get(handle);
313 final WriteOperationType p4Operation;
314 if (driverOperation == APPLY) {
315 if (piEntryOnDevice == null) {
316 // Entry is first-timer.
317 p4Operation = INSERT;
318 } else {
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800319 if (driverBoolProperty(IGNORE_SAME_ENTRY_UPDATE,
320 DEFAULT_IGNORE_SAME_ENTRY_UPDATE)
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800321 && piEntryToApply.action().equals(piEntryOnDevice.entry().action())) {
322 log.debug("Ignoring re-apply of existing entry: {}", piEntryToApply);
323 p4Operation = null;
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800324 } else if (driverBoolProperty(DELETE_BEFORE_UPDATE,
325 DEFAULT_DELETE_BEFORE_UPDATE)) {
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800326 // Some devices return error when updating existing
327 // entries. If requested, remove entry before
328 // re-inserting the modified one.
329 applyEntry(handle, piEntryOnDevice.entry(), null, REMOVE);
330 p4Operation = INSERT;
331 } else {
332 p4Operation = MODIFY;
333 }
334 }
335 } else {
336 p4Operation = DELETE;
337 }
338
339 if (p4Operation != null) {
340 if (writeEntry(piEntryToApply, p4Operation)) {
341 updateStores(handle, piEntryToApply, ruleToApply, p4Operation);
342 return true;
343 } else {
344 return false;
345 }
346 } else {
347 // If no operation, let's pretend we applied the rule to the device.
348 return true;
349 }
350 }
351
352 /**
353 * Performs a write operation on the device.
354 */
355 private boolean writeEntry(PiTableEntry entry,
356 WriteOperationType p4Operation) {
357 try {
358 if (client.writeTableEntries(
359 newArrayList(entry), p4Operation, pipeconf).get()) {
360 return true;
361 } else {
362 log.warn("Unable to {} table entry in {}: {}",
363 p4Operation.name(), deviceId, entry);
364 }
365 } catch (InterruptedException | ExecutionException e) {
366 log.warn("Exception while performing {} table entry operation:",
367 p4Operation, e);
368 }
369 return false;
370 }
371
372 private void updateStores(PiTableEntryHandle handle,
373 PiTableEntry entry,
374 FlowRule rule,
375 WriteOperationType p4Operation) {
376 switch (p4Operation) {
377 case INSERT:
378 case MODIFY:
379 tableMirror.put(handle, entry);
380 translator.learn(handle, new PiTranslatedEntity<>(rule, entry, handle));
381 break;
382 case DELETE:
383 tableMirror.remove(handle);
384 translator.forget(handle);
385 break;
386 default:
387 throw new IllegalArgumentException(
388 "Unknown operation " + p4Operation.name());
389 }
390 }
391
392 private Map<PiTableEntry, PiCounterCellData> readEntryCounters(
Carmelo Cascone255125d2018-04-11 14:03:22 -0700393 Collection<PiTableEntry> tableEntries) {
394 if (!driverBoolProperty(SUPPORT_TABLE_COUNTERS,
395 DEFAULT_SUPPORT_TABLE_COUNTERS)) {
396 return Collections.emptyMap();
397 }
398
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800399 Collection<PiCounterCellData> cellDatas;
400 try {
Carmelo Cascone3da671a2018-02-12 10:43:35 -0800401 if (driverBoolProperty(READ_ALL_DIRECT_COUNTERS,
402 DEFAULT_READ_ALL_DIRECT_COUNTERS)) {
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700403 // FIXME: re-implement reading all counters ONOS-7595, or
404 // (even better) read counters when dumping table entries ONOS-7596
405 // cellDatas = client.readAllCounterCells(
406 // singleton(counterId), pipeconf).get();
407 cellDatas = Collections.emptyList();
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800408 } else {
409 Set<PiCounterCellId> cellIds = tableEntries.stream()
Carmelo Cascone255125d2018-04-11 14:03:22 -0700410 .filter(e -> tableHasCounter(e.table()))
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700411 .map(PiCounterCellId::ofDirect)
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800412 .collect(Collectors.toSet());
413 cellDatas = client.readCounterCells(cellIds, pipeconf).get();
414 }
415 return cellDatas.stream()
416 .collect(Collectors.toMap(c -> c.cellId().tableEntry(), c -> c));
417 } catch (InterruptedException | ExecutionException e) {
418 if (!(e.getCause() instanceof StatusRuntimeException)) {
419 // gRPC errors are logged in the client.
Carmelo Cascone255125d2018-04-11 14:03:22 -0700420 log.error("Exception while reading table counters from {}: {}",
421 deviceId, e);
Carmelo Cascone6a0b5a32017-11-20 23:08:32 -0800422 }
423 return Collections.emptyMap();
424 }
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200425 }
426
Carmelo Cascone255125d2018-04-11 14:03:22 -0700427 private boolean tableHasCounter(PiTableId tableId) {
428 return pipelineModel.table(tableId).isPresent() &&
429 !pipelineModel.table(tableId).get().counters().isEmpty();
430 }
431
Carmelo Cascone0b22d8f2017-07-31 07:22:27 +0200432 enum Operation {
433 APPLY, REMOVE
Frank Wang0e805082017-07-21 14:37:35 +0800434 }
Carmelo Cascone87892e22017-11-13 16:01:29 -0800435}