blob: 081e0f157caccbd062105b515a780dc2fd54af9c [file] [log] [blame]
Carmelo Casconeb045ddc2017-09-01 01:26:35 +02001/*
2 * Copyright 2017-present 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.p4runtime;
18
19import com.google.common.collect.Maps;
20import com.google.common.collect.Sets;
21import org.onosproject.net.device.DefaultPortStatistics;
22import org.onosproject.net.device.PortStatistics;
23import org.onosproject.net.device.PortStatisticsDiscovery;
24import org.onosproject.net.pi.runtime.PiCounterCellData;
25import org.onosproject.net.pi.runtime.PiCounterCellId;
26import org.onosproject.net.pi.runtime.PiCounterId;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020027import org.onosproject.net.pi.runtime.PiIndirectCounterCellId;
Carmelo Casconeb045ddc2017-09-01 01:26:35 +020028
29import java.util.Collection;
30import java.util.Collections;
31import java.util.Map;
32import java.util.Set;
33import java.util.concurrent.ExecutionException;
34import java.util.stream.Collectors;
35
Carmelo Cascone7f75be42017-09-07 14:37:02 +020036import static org.onosproject.net.pi.runtime.PiCounterType.INDIRECT;
37
Carmelo Casconeb045ddc2017-09-01 01:26:35 +020038/**
39 * Implementation of a PortStatisticsBehaviour that can be used for any P4 program based on default.p4 (i.e. those
40 * under onos/tools/test/p4src).
41 */
42public class DefaultP4PortStatisticsDiscovery extends AbstractP4RuntimeHandlerBehaviour
43 implements PortStatisticsDiscovery {
44
Carmelo Casconecb0a49c2017-10-03 14:32:23 +020045 // FIXME: hard-coding the scope here will break support for the P4_14 version of the program.
46 // With P4_14, counter names in the generated P4Info won't have any scope.
47 // A solution could be that of dynamically building counter IDs based on the P4Info (as in DefaultP4Interpreter).
48 private static final String DEFAULT_SCOPE = "port_counters_control";
49 private static final String INGRESS_COUNTER = "ingress_port_counter";
50 private static final String EGRESS_COUNTER = "egress_port_counter";
51
52 /**
53 * Returns the scope string to be used for the counter IDs.
54 *
55 * @return scope string
56 */
57 public String scope() {
58 return DEFAULT_SCOPE;
59 }
Carmelo Casconeb045ddc2017-09-01 01:26:35 +020060
61 @Override
62 public Collection<PortStatistics> discoverPortStatistics() {
63
64 if (!super.setupBehaviour()) {
65 return Collections.emptyList();
66 }
67
Carmelo Casconecb0a49c2017-10-03 14:32:23 +020068 final PiCounterId ingressCounterId = PiCounterId.of(scope(), INGRESS_COUNTER, INDIRECT);
69 final PiCounterId egressCounterId = PiCounterId.of(scope(), EGRESS_COUNTER, INDIRECT);
70
Carmelo Casconeb045ddc2017-09-01 01:26:35 +020071 Map<Long, DefaultPortStatistics.Builder> portStatBuilders = Maps.newHashMap();
72
73 deviceService.getPorts(deviceId)
74 .forEach(p -> portStatBuilders.put(p.number().toLong(),
75 DefaultPortStatistics.builder()
Carmelo Cascone7f75be42017-09-07 14:37:02 +020076 .setPort(p.number())
Carmelo Casconeb045ddc2017-09-01 01:26:35 +020077 .setDeviceId(deviceId)));
78
79 Set<PiCounterCellId> counterCellIds = Sets.newHashSet();
80 portStatBuilders.keySet().forEach(p -> {
81 // Counter cell/index = port number.
Carmelo Casconecb0a49c2017-10-03 14:32:23 +020082 counterCellIds.add(PiIndirectCounterCellId.of(ingressCounterId, p));
83 counterCellIds.add(PiIndirectCounterCellId.of(egressCounterId, p));
Carmelo Casconeb045ddc2017-09-01 01:26:35 +020084 });
85
86 Collection<PiCounterCellData> counterEntryResponse;
87 try {
88 counterEntryResponse = client.readCounterCells(counterCellIds, pipeconf).get();
89 } catch (InterruptedException | ExecutionException e) {
90 log.warn("Exception while reading port counters from {}: {}", deviceId, e.toString());
91 log.debug("", e);
92 return Collections.emptyList();
93 }
94
Carmelo Cascone7f75be42017-09-07 14:37:02 +020095 counterEntryResponse.forEach(counterData -> {
96 if (counterData.cellId().type() != INDIRECT) {
97 log.warn("Invalid counter data type {}, skipping", counterData.cellId().type());
Carmelo Casconeb045ddc2017-09-01 01:26:35 +020098 return;
99 }
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200100 PiIndirectCounterCellId indCellId = (PiIndirectCounterCellId) counterData.cellId();
101 if (!portStatBuilders.containsKey(indCellId.index())) {
102 log.warn("Unrecognized counter index {}, skipping", counterData);
103 return;
104 }
105 DefaultPortStatistics.Builder statsBuilder = portStatBuilders.get(indCellId.index());
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200106 if (counterData.cellId().counterId().equals(ingressCounterId)) {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200107 statsBuilder.setPacketsReceived(counterData.packets());
108 statsBuilder.setBytesReceived(counterData.bytes());
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200109 } else if (counterData.cellId().counterId().equals(egressCounterId)) {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200110 statsBuilder.setPacketsSent(counterData.packets());
111 statsBuilder.setBytesSent(counterData.bytes());
Carmelo Casconeb045ddc2017-09-01 01:26:35 +0200112 } else {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200113 log.warn("Unrecognized counter ID {}, skipping", counterData);
Carmelo Casconeb045ddc2017-09-01 01:26:35 +0200114 }
115 });
116
117 return portStatBuilders
118 .values()
119 .stream()
120 .map(DefaultPortStatistics.Builder::build)
121 .collect(Collectors.toList());
122 }
123}