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