blob: 8a32232478c3b8c6a7d29d4e29e1d1d9eb364a7c [file] [log] [blame]
hjtsao1e8a1bd2018-10-22 11:02:00 -07001/*
2 * Copyright 2018-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 */
16package org.onosproject.drivers.p4runtime;
17
18import org.onosproject.net.DeviceId;
19import org.onosproject.net.behaviour.TableStatisticsDiscovery;
hjtsao1e8a1bd2018-10-22 11:02:00 -070020import org.onosproject.net.flow.DefaultTableStatisticsEntry;
Carmelo Casconec32976e2019-04-08 14:50:52 -070021import org.onosproject.net.flow.FlowEntry;
22import org.onosproject.net.flow.FlowRuleService;
23import org.onosproject.net.flow.IndexTableId;
24import org.onosproject.net.flow.TableId;
25import org.onosproject.net.flow.TableStatisticsEntry;
hjtsao1e8a1bd2018-10-22 11:02:00 -070026import org.onosproject.net.pi.model.PiPipelineInterpreter;
Carmelo Casconec32976e2019-04-08 14:50:52 -070027import org.onosproject.net.pi.model.PiPipelineModel;
hjtsao1e8a1bd2018-10-22 11:02:00 -070028import org.onosproject.net.pi.model.PiTableId;
29import org.onosproject.net.pi.model.PiTableModel;
30
Carmelo Casconec32976e2019-04-08 14:50:52 -070031import java.util.ArrayList;
hjtsao1e8a1bd2018-10-22 11:02:00 -070032import java.util.Collections;
hjtsao1e8a1bd2018-10-22 11:02:00 -070033import java.util.HashMap;
34import java.util.Iterator;
Carmelo Casconec32976e2019-04-08 14:50:52 -070035import java.util.List;
36import java.util.Map;
hjtsao1e8a1bd2018-10-22 11:02:00 -070037
38import static com.google.common.collect.Lists.newArrayList;
Carmelo Casconec2be50a2019-04-10 00:15:39 -070039import static org.onosproject.drivers.p4runtime.P4RuntimeDriverUtils.getInterpreter;
hjtsao1e8a1bd2018-10-22 11:02:00 -070040
41/**
42 * Implementation of behaviour TableStatisticsDiscovery for P4Runtime.
43 */
44public class P4RuntimeTableStatisticsDiscovery extends AbstractP4RuntimeHandlerBehaviour
45 implements TableStatisticsDiscovery {
46
47 @Override
48 public List<TableStatisticsEntry> getTableStatistics() {
Carmelo Casconec32976e2019-04-08 14:50:52 -070049 if (!setupBehaviour("getTableStatistics()")) {
hjtsao1e8a1bd2018-10-22 11:02:00 -070050 return Collections.emptyList();
51 }
52 FlowRuleService flowService = handler().get(FlowRuleService.class);
Carmelo Casconec2be50a2019-04-10 00:15:39 -070053 PiPipelineInterpreter interpreter = getInterpreter(handler());
hjtsao1e8a1bd2018-10-22 11:02:00 -070054 PiPipelineModel model = pipeconf.pipelineModel();
55 List<TableStatisticsEntry> tableStatsList;
56
57 List<FlowEntry> rules = newArrayList(flowService.getFlowEntries(deviceId));
58 Map<PiTableId, Integer> piTableFlowCount = piFlowRuleCounting(model, interpreter, rules);
59 Map<PiTableId, Long> piTableMatchCount = piMatchedCounting(model, interpreter, rules);
60 tableStatsList = generatePiFlowTableStatistics(piTableFlowCount, piTableMatchCount, model, deviceId);
61
62 return tableStatsList;
63 }
64
65 /**
66 * Returns the number of added flows in each table.
67 *
68 * @param model pipeline model
69 * @param interpreter pipeline interpreter
70 * @param rules flow rules in this device
71 * @return hashmap containing matched packet counting for each table
72 */
73 private Map<PiTableId, Integer> piFlowRuleCounting(PiPipelineModel model, PiPipelineInterpreter interpreter,
74 List<FlowEntry> rules) {
75 Map<PiTableId, Integer> piTableFlowCount = new HashMap<>();
76 for (PiTableModel tableModel : model.tables()) {
77 piTableFlowCount.put(tableModel.id(), 0);
78 }
79 for (FlowEntry f : rules) {
80 if (f.state() == FlowEntry.FlowEntryState.ADDED) {
81 PiTableId piTableId = getPiTableId(f, interpreter);
82 if (piTableId != null) {
83 piTableFlowCount.put(piTableId, piTableFlowCount.get(piTableId) + 1);
84 }
85 }
86 }
87 return piTableFlowCount;
88 }
89
90 /**
91 * Returns the number of matched packets for each table.
92 *
93 * @param model pipeline model
94 * @param interpreter pipeline interpreter
95 * @param rules flow rules in this device
96 * @return hashmap containing flow rule counting for each table
97 */
98 private Map<PiTableId, Long> piMatchedCounting(PiPipelineModel model, PiPipelineInterpreter interpreter,
99 List<FlowEntry> rules) {
100 Map<PiTableId, Long> piTableMatchCount = new HashMap<>();
101 for (PiTableModel tableModel : model.tables()) {
102 piTableMatchCount.put(tableModel.id(), (long) 0);
103 }
104 for (FlowEntry f : rules) {
105 if (f.state() == FlowEntry.FlowEntryState.ADDED) {
106 PiTableId piTableId = getPiTableId(f, interpreter);
107 if (piTableId != null) {
108 piTableMatchCount.put(piTableId, piTableMatchCount.get(piTableId) + f.packets());
109 }
110 }
111 }
112 return piTableMatchCount;
113 }
114
115 /**
116 * Returns the PiTableId of the pipeline independent table that contains the flow rule. If null is returned, it
117 * means that the given flow rule's table ID is index table ID without a mapping with a pipeline independent table
118 * ID.
119 *
120 * @param flowEntry flow rule
121 * @param interpreter pipeline interpreter
122 * @return PiTableId of the table containing input FlowEntry or null
123 */
124 private PiTableId getPiTableId(FlowEntry flowEntry, PiPipelineInterpreter interpreter) {
125 return flowEntry.table().type() == TableId.Type.PIPELINE_INDEPENDENT ? (PiTableId) flowEntry.table() :
126 interpreter.mapFlowRuleTableId(((IndexTableId) flowEntry.table()).id()).orElse(null);
127 }
128
129 /**
130 * Returns the list of table statistics for P4 switch.
131 *
132 * @param piTableFlowCount hashmap containing the number of flow rules for each table
133 * @param piTableMatchCount hashmap containing the number of matched packets for each table
134 * @param model pipeline model
135 * @param deviceId device ID
136 * @return list of table statistics for P4 switch
137 */
138 private List<TableStatisticsEntry> generatePiFlowTableStatistics(Map<PiTableId, Integer> piTableFlowCount,
139 Map<PiTableId, Long> piTableMatchCount,
140 PiPipelineModel model, DeviceId deviceId) {
141 List<TableStatisticsEntry> tableStatsList;
142 Iterator it = piTableFlowCount.entrySet().iterator();
143 tableStatsList = new ArrayList<>();
144 while (it.hasNext()) {
145 Map.Entry pair = (Map.Entry) it.next();
146 TableStatisticsEntry tableStat = DefaultTableStatisticsEntry.builder()
147 .withDeviceId(deviceId)
148 .withTableId((PiTableId) pair.getKey())
149 .withActiveFlowEntries(piTableFlowCount.get(pair.getKey()))
150 .withPacketsMatchedCount(piTableMatchCount.get(pair.getKey()))
151 .withMaxSize(model.table((PiTableId) pair.getKey()).get().maxSize()).build();
152 tableStatsList.add(tableStat);
153 it.remove();
154 }
155 return tableStatsList;
156 }
157}