Committed by
Jonathan Hart
Improve flow rule polling consistency with bmv2
Change-Id: Iee5e7d7bee8f16505fe4d2acf48e65775bb2a524
Showing
3 changed files
with
61 additions
and
18 deletions
... | @@ -22,6 +22,7 @@ import com.google.common.cache.CacheLoader; | ... | @@ -22,6 +22,7 @@ import com.google.common.cache.CacheLoader; |
22 | import com.google.common.cache.LoadingCache; | 22 | import com.google.common.cache.LoadingCache; |
23 | import com.google.common.collect.Lists; | 23 | import com.google.common.collect.Lists; |
24 | import com.google.common.collect.Maps; | 24 | import com.google.common.collect.Maps; |
25 | +import com.google.common.collect.Sets; | ||
25 | import org.apache.commons.lang3.tuple.Pair; | 26 | import org.apache.commons.lang3.tuple.Pair; |
26 | import org.apache.commons.lang3.tuple.Triple; | 27 | import org.apache.commons.lang3.tuple.Triple; |
27 | import org.onosproject.bmv2.api.model.Bmv2Model; | 28 | import org.onosproject.bmv2.api.model.Bmv2Model; |
... | @@ -48,6 +49,7 @@ import org.slf4j.LoggerFactory; | ... | @@ -48,6 +49,7 @@ import org.slf4j.LoggerFactory; |
48 | import java.util.Collection; | 49 | import java.util.Collection; |
49 | import java.util.Collections; | 50 | import java.util.Collections; |
50 | import java.util.List; | 51 | import java.util.List; |
52 | +import java.util.Set; | ||
51 | import java.util.concurrent.ConcurrentMap; | 53 | import java.util.concurrent.ConcurrentMap; |
52 | import java.util.concurrent.ExecutionException; | 54 | import java.util.concurrent.ExecutionException; |
53 | import java.util.concurrent.TimeUnit; | 55 | import java.util.concurrent.TimeUnit; |
... | @@ -61,7 +63,8 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour | ... | @@ -61,7 +63,8 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour |
61 | private static final Logger LOG = | 63 | private static final Logger LOG = |
62 | LoggerFactory.getLogger(Bmv2FlowRuleProgrammable.class); | 64 | LoggerFactory.getLogger(Bmv2FlowRuleProgrammable.class); |
63 | 65 | ||
64 | - // There's no Bmv2 client method to poll flow entries from the device device. Need a local store. | 66 | + // 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. | ||
65 | private static final ConcurrentMap<Triple<DeviceId, String, Bmv2MatchKey>, Pair<Long, FlowEntry>> | 68 | private static final ConcurrentMap<Triple<DeviceId, String, Bmv2MatchKey>, Pair<Long, FlowEntry>> |
66 | ENTRIES_MAP = Maps.newConcurrentMap(); | 69 | ENTRIES_MAP = Maps.newConcurrentMap(); |
67 | 70 | ||
... | @@ -81,12 +84,41 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour | ... | @@ -81,12 +84,41 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour |
81 | 84 | ||
82 | DeviceId deviceId = handler().data().deviceId(); | 85 | DeviceId deviceId = handler().data().deviceId(); |
83 | 86 | ||
87 | + Bmv2Client deviceClient; | ||
88 | + try { | ||
89 | + deviceClient = Bmv2ThriftClient.of(deviceId); | ||
90 | + } catch (Bmv2RuntimeException e) { | ||
91 | + LOG.error("Failed to connect to Bmv2 device", e); | ||
92 | + return Collections.emptyList(); | ||
93 | + } | ||
94 | + | ||
95 | + Bmv2Model model = getTranslator(deviceId).config().model(); | ||
96 | + | ||
84 | List<FlowEntry> entryList = Lists.newArrayList(); | 97 | List<FlowEntry> entryList = Lists.newArrayList(); |
85 | 98 | ||
86 | - // FIXME: improve this, e.g. might store a separate Map<DeviceId, Collection<FlowEntry>> | 99 | + model.tables().forEach(table -> { |
87 | - ENTRIES_MAP.forEach((key, value) -> { | 100 | + // For each table declared in the model for this device, do: |
88 | - if (key.getLeft() == deviceId && value != null) { | 101 | + try { |
89 | - entryList.add(value.getRight()); | 102 | + // Bmv2 doesn't support proper polling for table entries, but only a string based table dump. |
103 | + // The trick here is to first dump the entry ids currently installed in the device for a given table, | ||
104 | + // and then filter ENTRIES_MAP based on the retrieved values. | ||
105 | + Set<Long> installedEntryIds = Sets.newHashSet(deviceClient.getInstalledEntryIds(table.name())); | ||
106 | + ENTRIES_MAP.forEach((key, value) -> { | ||
107 | + if (key.getLeft() == deviceId && key.getMiddle() == table.name() | ||
108 | + && value != null) { | ||
109 | + // Filter entries_map for this device and table. | ||
110 | + if (installedEntryIds.contains(value.getKey())) { | ||
111 | + // Entry is installed. | ||
112 | + entryList.add(value.getRight()); | ||
113 | + } else { | ||
114 | + // No such entry on device, can remove from local store. | ||
115 | + ENTRIES_MAP.remove(key); | ||
116 | + } | ||
117 | + } | ||
118 | + }); | ||
119 | + } catch (Bmv2RuntimeException e) { | ||
120 | + LOG.error("Unable to get flow entries for table {} of device {}: {}", | ||
121 | + table.name(), deviceId, e.toString()); | ||
90 | } | 122 | } |
91 | }); | 123 | }); |
92 | 124 | ||
... | @@ -144,16 +176,19 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour | ... | @@ -144,16 +176,19 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour |
144 | if (operation == Operation.APPLY) { | 176 | if (operation == Operation.APPLY) { |
145 | // Apply entry | 177 | // Apply entry |
146 | long entryId; | 178 | long entryId; |
147 | - if (value == null) { | 179 | + if (value != null) { |
148 | - // New entry | 180 | + // Existing entry. |
149 | - entryId = deviceClient.addTableEntry(bmv2Entry); | ||
150 | - } else { | ||
151 | - // Existing entry | ||
152 | entryId = value.getKey(); | 181 | entryId = value.getKey(); |
153 | - // FIXME: check if priority or timeout changed | 182 | + try { |
154 | - // In this case we should to re-add the entry (not modify) | 183 | + // Tentatively delete entry before re-adding. |
155 | - deviceClient.modifyTableEntry(tableName, entryId, bmv2Entry.action()); | 184 | + // It might not exist on device due to inconsistencies. |
185 | + deviceClient.deleteTableEntry(bmv2Entry.tableName(), entryId); | ||
186 | + } catch (Bmv2RuntimeException e) { | ||
187 | + // Silently drop exception as we can probably fix this by re-adding the entry. | ||
188 | + } | ||
156 | } | 189 | } |
190 | + // Add entry. | ||
191 | + entryId = deviceClient.addTableEntry(bmv2Entry); | ||
157 | // TODO: evaluate flow entry life, bytes and packets | 192 | // TODO: evaluate flow entry life, bytes and packets |
158 | FlowEntry flowEntry = new DefaultFlowEntry( | 193 | FlowEntry flowEntry = new DefaultFlowEntry( |
159 | rule, FlowEntry.FlowEntryState.ADDED, 0, 0, 0); | 194 | rule, FlowEntry.FlowEntryState.ADDED, 0, 0, 0); |
... | @@ -171,9 +206,7 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour | ... | @@ -171,9 +206,7 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour |
171 | // If here, no exceptions... things went well :) | 206 | // If here, no exceptions... things went well :) |
172 | processedFlowRules.add(rule); | 207 | processedFlowRules.add(rule); |
173 | } catch (Bmv2RuntimeException e) { | 208 | } catch (Bmv2RuntimeException e) { |
174 | - LOG.error("Unable to " + operation.name().toLowerCase() + " flow rule", e); | 209 | + LOG.warn("Unable to {} flow rule: {}", operation.name().toLowerCase(), e.toString()); |
175 | - } catch (Exception e) { | ||
176 | - LOG.error("Uncaught exception while processing flow rule", e); | ||
177 | } | 210 | } |
178 | return value; | 211 | return value; |
179 | }); | 212 | }); | ... | ... |
... | @@ -39,7 +39,7 @@ import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT; | ... | @@ -39,7 +39,7 @@ import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT; |
39 | public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements PacketProgrammable { | 39 | public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements PacketProgrammable { |
40 | 40 | ||
41 | private static final Logger LOG = | 41 | private static final Logger LOG = |
42 | - LoggerFactory.getLogger(Bmv2FlowRuleProgrammable.class); | 42 | + LoggerFactory.getLogger(Bmv2PacketProgrammable.class); |
43 | 43 | ||
44 | @Override | 44 | @Override |
45 | public void emit(OutboundPacket packet) { | 45 | public void emit(OutboundPacket packet) { | ... | ... |
... | @@ -182,6 +182,8 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -182,6 +182,8 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
182 | DeviceDescription descr = new DefaultDeviceDescription( | 182 | DeviceDescription descr = new DefaultDeviceDescription( |
183 | did.uri(), Device.Type.SWITCH, MANUFACTURER, HW_VERSION, | 183 | did.uri(), Device.Type.SWITCH, MANUFACTURER, HW_VERSION, |
184 | UNKNOWN, UNKNOWN, new ChassisId(), annotationsBuilder.build()); | 184 | UNKNOWN, UNKNOWN, new ChassisId(), annotationsBuilder.build()); |
185 | + // Reset device state (cleanup entries, etc.) | ||
186 | + resetDeviceState(did); | ||
185 | providerService.deviceConnected(did, descr); | 187 | providerService.deviceConnected(did, descr); |
186 | } | 188 | } |
187 | updatePorts(did); | 189 | updatePorts(did); |
... | @@ -199,7 +201,15 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -199,7 +201,15 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
199 | builder.set("bmv2JsonConfigMd5", md5); | 201 | builder.set("bmv2JsonConfigMd5", md5); |
200 | builder.set("bmv2JsonConfigValue", jsonString); | 202 | builder.set("bmv2JsonConfigValue", jsonString); |
201 | } catch (Bmv2RuntimeException e) { | 203 | } catch (Bmv2RuntimeException e) { |
202 | - LOG.warn("Unable to dump device JSON config from device {}: {}", did, e); | 204 | + LOG.warn("Unable to dump device JSON config from device {}: {}", did, e.toString()); |
205 | + } | ||
206 | + } | ||
207 | + | ||
208 | + private void resetDeviceState(DeviceId did) { | ||
209 | + try { | ||
210 | + Bmv2ThriftClient.of(did).resetState(); | ||
211 | + } catch (Bmv2RuntimeException e) { | ||
212 | + LOG.warn("Unable to reset {}: {}", did, e.toString()); | ||
203 | } | 213 | } |
204 | } | 214 | } |
205 | 215 | ... | ... |
-
Please register or login to post a comment