Committed by
Ray Milkey
Added ability to poll flow counters in BMv2
Also fixed few minor things here and there. Change-Id: Ib5e6a92de46870f52510cd6fad0cef8da022bb62
Showing
5 changed files
with
76 additions
and
9 deletions
... | @@ -48,12 +48,15 @@ import org.slf4j.LoggerFactory; | ... | @@ -48,12 +48,15 @@ import org.slf4j.LoggerFactory; |
48 | 48 | ||
49 | import java.util.Collection; | 49 | import java.util.Collection; |
50 | import java.util.Collections; | 50 | import java.util.Collections; |
51 | +import java.util.Date; | ||
51 | import java.util.List; | 52 | import java.util.List; |
52 | import java.util.Set; | 53 | import java.util.Set; |
53 | import java.util.concurrent.ConcurrentMap; | 54 | import java.util.concurrent.ConcurrentMap; |
54 | import java.util.concurrent.ExecutionException; | 55 | import java.util.concurrent.ExecutionException; |
55 | import java.util.concurrent.TimeUnit; | 56 | import java.util.concurrent.TimeUnit; |
56 | 57 | ||
58 | +import static org.onosproject.net.flow.FlowEntry.FlowEntryState.ADDED; | ||
59 | + | ||
57 | /** | 60 | /** |
58 | * Flow rule programmable device behaviour implementation for BMv2. | 61 | * Flow rule programmable device behaviour implementation for BMv2. |
59 | */ | 62 | */ |
... | @@ -65,7 +68,7 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour | ... | @@ -65,7 +68,7 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour |
65 | 68 | ||
66 | // There's no Bmv2 client method to poll flow entries from the device. Use a local store. | 69 | // There's no Bmv2 client method to poll flow entries from the device. Use a local store. |
67 | // FIXME: this information should be distributed across instances of the cluster. | 70 | // FIXME: this information should be distributed across instances of the cluster. |
68 | - private static final ConcurrentMap<Triple<DeviceId, String, Bmv2MatchKey>, Pair<Long, FlowEntry>> | 71 | + private static final ConcurrentMap<Triple<DeviceId, String, Bmv2MatchKey>, Pair<Long, TimestampedFlowRule>> |
69 | ENTRIES_MAP = Maps.newConcurrentMap(); | 72 | ENTRIES_MAP = Maps.newConcurrentMap(); |
70 | 73 | ||
71 | // Cache model objects instead of parsing the JSON each time. | 74 | // Cache model objects instead of parsing the JSON each time. |
... | @@ -106,10 +109,28 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour | ... | @@ -106,10 +109,28 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour |
106 | ENTRIES_MAP.forEach((key, value) -> { | 109 | ENTRIES_MAP.forEach((key, value) -> { |
107 | if (key.getLeft() == deviceId && key.getMiddle() == table.name() | 110 | if (key.getLeft() == deviceId && key.getMiddle() == table.name() |
108 | && value != null) { | 111 | && value != null) { |
112 | + long entryId = value.getKey(); | ||
109 | // Filter entries_map for this device and table. | 113 | // Filter entries_map for this device and table. |
110 | - if (installedEntryIds.contains(value.getKey())) { | 114 | + if (installedEntryIds.contains(entryId)) { |
111 | // Entry is installed. | 115 | // Entry is installed. |
112 | - entryList.add(value.getRight()); | 116 | + long bytes = 0L; |
117 | + long packets = 0L; | ||
118 | + if (table.hasCounters()) { | ||
119 | + // Read counter values from device. | ||
120 | + try { | ||
121 | + Pair<Long, Long> counterValue = deviceClient.readTableEntryCounter(table.name(), | ||
122 | + entryId); | ||
123 | + bytes = counterValue.getLeft(); | ||
124 | + packets = counterValue.getRight(); | ||
125 | + } catch (Bmv2RuntimeException e) { | ||
126 | + LOG.warn("Unable to get counter values for entry {} of table {} of device {}: {}", | ||
127 | + entryId, table.name(), deviceId, e.toString()); | ||
128 | + } | ||
129 | + } | ||
130 | + TimestampedFlowRule tsRule = value.getRight(); | ||
131 | + FlowEntry entry = new DefaultFlowEntry(tsRule.rule(), ADDED, | ||
132 | + tsRule.lifeInSeconds(), packets, bytes); | ||
133 | + entryList.add(entry); | ||
113 | } else { | 134 | } else { |
114 | // No such entry on device, can remove from local store. | 135 | // No such entry on device, can remove from local store. |
115 | ENTRIES_MAP.remove(key); | 136 | ENTRIES_MAP.remove(key); |
... | @@ -183,16 +204,14 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour | ... | @@ -183,16 +204,14 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour |
183 | // Tentatively delete entry before re-adding. | 204 | // Tentatively delete entry before re-adding. |
184 | // It might not exist on device due to inconsistencies. | 205 | // It might not exist on device due to inconsistencies. |
185 | deviceClient.deleteTableEntry(bmv2Entry.tableName(), entryId); | 206 | deviceClient.deleteTableEntry(bmv2Entry.tableName(), entryId); |
207 | + value = null; | ||
186 | } catch (Bmv2RuntimeException e) { | 208 | } catch (Bmv2RuntimeException e) { |
187 | // Silently drop exception as we can probably fix this by re-adding the entry. | 209 | // Silently drop exception as we can probably fix this by re-adding the entry. |
188 | } | 210 | } |
189 | } | 211 | } |
190 | // Add entry. | 212 | // Add entry. |
191 | entryId = deviceClient.addTableEntry(bmv2Entry); | 213 | entryId = deviceClient.addTableEntry(bmv2Entry); |
192 | - // TODO: evaluate flow entry life, bytes and packets | 214 | + value = Pair.of(entryId, new TimestampedFlowRule(rule)); |
193 | - FlowEntry flowEntry = new DefaultFlowEntry( | ||
194 | - rule, FlowEntry.FlowEntryState.ADDED, 0, 0, 0); | ||
195 | - value = Pair.of(entryId, flowEntry); | ||
196 | } else { | 215 | } else { |
197 | // Remove entry | 216 | // Remove entry |
198 | if (value == null) { | 217 | if (value == null) { |
... | @@ -258,4 +277,22 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour | ... | @@ -258,4 +277,22 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour |
258 | private enum Operation { | 277 | private enum Operation { |
259 | APPLY, REMOVE | 278 | APPLY, REMOVE |
260 | } | 279 | } |
280 | + | ||
281 | + private class TimestampedFlowRule { | ||
282 | + private final FlowRule rule; | ||
283 | + private final Date addedDate; | ||
284 | + | ||
285 | + public TimestampedFlowRule(FlowRule rule) { | ||
286 | + this.rule = rule; | ||
287 | + this.addedDate = new Date(); | ||
288 | + } | ||
289 | + | ||
290 | + public FlowRule rule() { | ||
291 | + return rule; | ||
292 | + } | ||
293 | + | ||
294 | + public long lifeInSeconds() { | ||
295 | + return (new Date().getTime() - addedDate.getTime()) / 1000; | ||
296 | + } | ||
297 | + } | ||
261 | } | 298 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -115,7 +115,7 @@ public final class Bmv2ModelTable { | ... | @@ -115,7 +115,7 @@ public final class Bmv2ModelTable { |
115 | * | 115 | * |
116 | * @return a boolean value | 116 | * @return a boolean value |
117 | */ | 117 | */ |
118 | - public boolean hasCunters() { | 118 | + public boolean hasCounters() { |
119 | return hasCounters; | 119 | return hasCounters; |
120 | } | 120 | } |
121 | 121 | ... | ... |
... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
16 | 16 | ||
17 | package org.onosproject.bmv2.api.runtime; | 17 | package org.onosproject.bmv2.api.runtime; |
18 | 18 | ||
19 | +import org.apache.commons.lang3.tuple.Pair; | ||
19 | import org.onlab.util.ImmutableByteSequence; | 20 | import org.onlab.util.ImmutableByteSequence; |
20 | 21 | ||
21 | import java.util.Collection; | 22 | import java.util.Collection; |
... | @@ -132,4 +133,14 @@ public interface Bmv2Client { | ... | @@ -132,4 +133,14 @@ public interface Bmv2Client { |
132 | * @throws Bmv2RuntimeException if any error occurs | 133 | * @throws Bmv2RuntimeException if any error occurs |
133 | */ | 134 | */ |
134 | String getJsonConfigMd5() throws Bmv2RuntimeException; | 135 | String getJsonConfigMd5() throws Bmv2RuntimeException; |
136 | + | ||
137 | + /** | ||
138 | + * Returns the counter values for a given table and entry. | ||
139 | + * | ||
140 | + * @param tableName a table name | ||
141 | + * @param entryId an entry id | ||
142 | + * @return a pair of long values, where the left value is the number of bytes and the right the number of packets | ||
143 | + * @throws Bmv2RuntimeException if any error occurs | ||
144 | + */ | ||
145 | + Pair<Long, Long> readTableEntryCounter(String tableName, long entryId) throws Bmv2RuntimeException; | ||
135 | } | 146 | } | ... | ... |
... | @@ -44,6 +44,7 @@ import org.onosproject.bmv2.api.runtime.Bmv2TernaryMatchParam; | ... | @@ -44,6 +44,7 @@ import org.onosproject.bmv2.api.runtime.Bmv2TernaryMatchParam; |
44 | import org.onosproject.bmv2.api.runtime.Bmv2ValidMatchParam; | 44 | import org.onosproject.bmv2.api.runtime.Bmv2ValidMatchParam; |
45 | import org.onosproject.net.DeviceId; | 45 | import org.onosproject.net.DeviceId; |
46 | import org.p4.bmv2.thrift.BmAddEntryOptions; | 46 | import org.p4.bmv2.thrift.BmAddEntryOptions; |
47 | +import org.p4.bmv2.thrift.BmCounterValue; | ||
47 | import org.p4.bmv2.thrift.BmMatchParam; | 48 | import org.p4.bmv2.thrift.BmMatchParam; |
48 | import org.p4.bmv2.thrift.BmMatchParamExact; | 49 | import org.p4.bmv2.thrift.BmMatchParamExact; |
49 | import org.p4.bmv2.thrift.BmMatchParamLPM; | 50 | import org.p4.bmv2.thrift.BmMatchParamLPM; |
... | @@ -477,6 +478,24 @@ public final class Bmv2ThriftClient implements Bmv2Client { | ... | @@ -477,6 +478,24 @@ public final class Bmv2ThriftClient implements Bmv2Client { |
477 | } | 478 | } |
478 | 479 | ||
479 | @Override | 480 | @Override |
481 | + public Pair<Long, Long> readTableEntryCounter(String tableName, long entryId) throws Bmv2RuntimeException { | ||
482 | + | ||
483 | + LOG.debug("Reading table entry counters... > deviceId={}, tableName={}, entryId={}", | ||
484 | + deviceId, tableName, entryId); | ||
485 | + | ||
486 | + try { | ||
487 | + BmCounterValue counterValue = standardClient.bm_mt_read_counter(CONTEXT_ID, tableName, entryId); | ||
488 | + LOG.debug("Table entry counters retrieved! > deviceId={}, tableName={}, entryId={}, bytes={}, packets={}", | ||
489 | + deviceId, tableName, entryId, counterValue.bytes, counterValue.packets); | ||
490 | + return Pair.of(counterValue.bytes, counterValue.packets); | ||
491 | + } catch (TException e) { | ||
492 | + LOG.debug("Exception while reading table counters: {} > deviceId={}, tableName={}, entryId={}", | ||
493 | + e.toString(), deviceId); | ||
494 | + throw new Bmv2RuntimeException(e.getMessage(), e); | ||
495 | + } | ||
496 | + } | ||
497 | + | ||
498 | + @Override | ||
480 | public String getJsonConfigMd5() throws Bmv2RuntimeException { | 499 | public String getJsonConfigMd5() throws Bmv2RuntimeException { |
481 | 500 | ||
482 | LOG.debug("Getting device config md5... > deviceId={}", deviceId); | 501 | LOG.debug("Getting device config md5... > deviceId={}", deviceId); | ... | ... |
... | @@ -52,7 +52,7 @@ public class Bmv2ModelTest { | ... | @@ -52,7 +52,7 @@ public class Bmv2ModelTest { |
52 | @Test | 52 | @Test |
53 | public void testParse() throws Exception { | 53 | public void testParse() throws Exception { |
54 | Bmv2Model model = Bmv2Model.parse(json); | 54 | Bmv2Model model = Bmv2Model.parse(json); |
55 | - Bmv2Model model2 = Bmv2Model.parse(json); | 55 | + Bmv2Model model2 = Bmv2Model.parse(json2); |
56 | 56 | ||
57 | new EqualsTester() | 57 | new EqualsTester() |
58 | .addEqualityGroup(model, model2) | 58 | .addEqualityGroup(model, model2) | ... | ... |
-
Please register or login to post a comment