Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
Showing
94 changed files
with
3360 additions
and
807 deletions
... | @@ -5,8 +5,6 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -5,8 +5,6 @@ import static org.slf4j.LoggerFactory.getLogger; |
5 | import java.util.LinkedList; | 5 | import java.util.LinkedList; |
6 | import java.util.List; | 6 | import java.util.List; |
7 | 7 | ||
8 | -import com.codahale.metrics.Gauge; | ||
9 | -import com.codahale.metrics.Meter; | ||
10 | import com.google.common.collect.ImmutableList; | 8 | import com.google.common.collect.ImmutableList; |
11 | import org.apache.felix.scr.annotations.Activate; | 9 | import org.apache.felix.scr.annotations.Activate; |
12 | import org.apache.felix.scr.annotations.Component; | 10 | import org.apache.felix.scr.annotations.Component; |
... | @@ -14,8 +12,7 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -14,8 +12,7 @@ import org.apache.felix.scr.annotations.Deactivate; |
14 | import org.apache.felix.scr.annotations.Reference; | 12 | import org.apache.felix.scr.annotations.Reference; |
15 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 13 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
16 | import org.apache.felix.scr.annotations.Service; | 14 | import org.apache.felix.scr.annotations.Service; |
17 | -import org.onlab.metrics.MetricsComponent; | 15 | +import org.onlab.metrics.EventMetric; |
18 | -import org.onlab.metrics.MetricsFeature; | ||
19 | import org.onlab.metrics.MetricsService; | 16 | import org.onlab.metrics.MetricsService; |
20 | import org.onlab.onos.net.intent.IntentEvent; | 17 | import org.onlab.onos.net.intent.IntentEvent; |
21 | import org.onlab.onos.net.intent.IntentListener; | 18 | import org.onlab.onos.net.intent.IntentListener; |
... | @@ -33,56 +30,32 @@ public class IntentMetrics implements IntentMetricsService, | ... | @@ -33,56 +30,32 @@ public class IntentMetrics implements IntentMetricsService, |
33 | 30 | ||
34 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 31 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
35 | protected IntentService intentService; | 32 | protected IntentService intentService; |
33 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
34 | + protected MetricsService metricsService; | ||
35 | + | ||
36 | private LinkedList<IntentEvent> lastEvents = new LinkedList<>(); | 36 | private LinkedList<IntentEvent> lastEvents = new LinkedList<>(); |
37 | private static final int LAST_EVENTS_MAX_N = 100; | 37 | private static final int LAST_EVENTS_MAX_N = 100; |
38 | 38 | ||
39 | // | 39 | // |
40 | // Metrics | 40 | // Metrics |
41 | // | 41 | // |
42 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
43 | - protected MetricsService metricsService; | ||
44 | - // | ||
45 | private static final String COMPONENT_NAME = "Intent"; | 42 | private static final String COMPONENT_NAME = "Intent"; |
46 | private static final String FEATURE_SUBMITTED_NAME = "Submitted"; | 43 | private static final String FEATURE_SUBMITTED_NAME = "Submitted"; |
47 | private static final String FEATURE_INSTALLED_NAME = "Installed"; | 44 | private static final String FEATURE_INSTALLED_NAME = "Installed"; |
48 | private static final String FEATURE_WITHDRAW_REQUESTED_NAME = | 45 | private static final String FEATURE_WITHDRAW_REQUESTED_NAME = |
49 | "WithdrawRequested"; | 46 | "WithdrawRequested"; |
50 | private static final String FEATURE_WITHDRAWN_NAME = "Withdrawn"; | 47 | private static final String FEATURE_WITHDRAWN_NAME = "Withdrawn"; |
51 | - private static final String GAUGE_TIMESTAMP_NAME = "Timestamp.EpochMs"; | ||
52 | - private static final String METER_RATE_NAME = "Rate"; | ||
53 | - // | ||
54 | - private MetricsComponent metricsComponent; | ||
55 | - private MetricsFeature metricsFeatureSubmitted; | ||
56 | - private MetricsFeature metricsFeatureInstalled; | ||
57 | - private MetricsFeature metricsFeatureWithdrawRequested; | ||
58 | - private MetricsFeature metricsFeatureWithdrawn; | ||
59 | - // | ||
60 | - // Timestamps: | ||
61 | - // - Intent Submitted API operation (ms from the Epoch) | ||
62 | - // - Intent Installed operation completion (ms from the Epoch) | ||
63 | - // - Intent Withdraw Requested API operation (ms from the Epoch) | ||
64 | - // - Intent Withdrawn operation completion (ms from the Epoch) | ||
65 | - // | ||
66 | - private volatile long intentSubmittedTimestampEpochMs = 0; | ||
67 | - private volatile long intentInstalledTimestampEpochMs = 0; | ||
68 | - private volatile long intentWithdrawRequestedTimestampEpochMs = 0; | ||
69 | - private volatile long intentWithdrawnTimestampEpochMs = 0; | ||
70 | - // | ||
71 | - private Gauge<Long> intentSubmittedTimestampEpochMsGauge; | ||
72 | - private Gauge<Long> intentInstalledTimestampEpochMsGauge; | ||
73 | - private Gauge<Long> intentWithdrawRequestedTimestampEpochMsGauge; | ||
74 | - private Gauge<Long> intentWithdrawnTimestampEpochMsGauge; | ||
75 | // | 48 | // |
76 | - // Rate meters: | 49 | + // Event metrics: |
77 | - // - Rate of the Submitted Intent API operations | 50 | + // - Intent Submitted API operation |
78 | - // - Rate of the Installed Intent operations | 51 | + // - Intent Installed operation completion |
79 | - // - Rate of the Withdrawn Requested Intent API operations | 52 | + // - Intent Withdraw Requested API operation |
80 | - // - Rate of the Withdrawn Intent operations | 53 | + // - Intent Withdrawn operation completion |
81 | // | 54 | // |
82 | - private Meter intentSubmittedRateMeter; | 55 | + private EventMetric intentSubmittedEventMetric; |
83 | - private Meter intentInstalledRateMeter; | 56 | + private EventMetric intentInstalledEventMetric; |
84 | - private Meter intentWithdrawRequestedRateMeter; | 57 | + private EventMetric intentWithdrawRequestedEventMetric; |
85 | - private Meter intentWithdrawnRateMeter; | 58 | + private EventMetric intentWithdrawnEventMetric; |
86 | 59 | ||
87 | @Activate | 60 | @Activate |
88 | protected void activate() { | 61 | protected void activate() { |
... | @@ -108,43 +81,23 @@ public class IntentMetrics implements IntentMetricsService, | ... | @@ -108,43 +81,23 @@ public class IntentMetrics implements IntentMetricsService, |
108 | } | 81 | } |
109 | 82 | ||
110 | @Override | 83 | @Override |
111 | - public Gauge<Long> intentSubmittedTimestampEpochMsGauge() { | 84 | + public EventMetric intentSubmittedEventMetric() { |
112 | - return intentSubmittedTimestampEpochMsGauge; | 85 | + return intentSubmittedEventMetric; |
113 | } | 86 | } |
114 | 87 | ||
115 | @Override | 88 | @Override |
116 | - public Gauge<Long> intentInstalledTimestampEpochMsGauge() { | 89 | + public EventMetric intentInstalledEventMetric() { |
117 | - return intentInstalledTimestampEpochMsGauge; | 90 | + return intentInstalledEventMetric; |
118 | } | 91 | } |
119 | 92 | ||
120 | @Override | 93 | @Override |
121 | - public Gauge<Long> intentWithdrawRequestedTimestampEpochMsGauge() { | 94 | + public EventMetric intentWithdrawRequestedEventMetric() { |
122 | - return intentWithdrawRequestedTimestampEpochMsGauge; | 95 | + return intentWithdrawRequestedEventMetric; |
123 | } | 96 | } |
124 | 97 | ||
125 | @Override | 98 | @Override |
126 | - public Gauge<Long> intentWithdrawnTimestampEpochMsGauge() { | 99 | + public EventMetric intentWithdrawnEventMetric() { |
127 | - return intentWithdrawnTimestampEpochMsGauge; | 100 | + return intentWithdrawnEventMetric; |
128 | - } | ||
129 | - | ||
130 | - @Override | ||
131 | - public Meter intentSubmittedRateMeter() { | ||
132 | - return intentSubmittedRateMeter; | ||
133 | - } | ||
134 | - | ||
135 | - @Override | ||
136 | - public Meter intentInstalledRateMeter() { | ||
137 | - return intentInstalledRateMeter; | ||
138 | - } | ||
139 | - | ||
140 | - @Override | ||
141 | - public Meter intentWithdrawRequestedRateMeter() { | ||
142 | - return intentWithdrawRequestedRateMeter; | ||
143 | - } | ||
144 | - | ||
145 | - @Override | ||
146 | - public Meter intentWithdrawnRateMeter() { | ||
147 | - return intentWithdrawnRateMeter; | ||
148 | } | 101 | } |
149 | 102 | ||
150 | @Override | 103 | @Override |
... | @@ -156,26 +109,21 @@ public class IntentMetrics implements IntentMetricsService, | ... | @@ -156,26 +109,21 @@ public class IntentMetrics implements IntentMetricsService, |
156 | // | 109 | // |
157 | switch (event.type()) { | 110 | switch (event.type()) { |
158 | case SUBMITTED: | 111 | case SUBMITTED: |
159 | - intentSubmittedTimestampEpochMs = System.currentTimeMillis(); | 112 | + intentSubmittedEventMetric.eventReceived(); |
160 | - intentSubmittedRateMeter.mark(1); | ||
161 | break; | 113 | break; |
162 | case INSTALLED: | 114 | case INSTALLED: |
163 | - intentInstalledTimestampEpochMs = System.currentTimeMillis(); | 115 | + intentInstalledEventMetric.eventReceived(); |
164 | - intentInstalledRateMeter.mark(1); | ||
165 | break; | 116 | break; |
166 | case FAILED: | 117 | case FAILED: |
167 | // TODO: Just ignore? | 118 | // TODO: Just ignore? |
168 | break; | 119 | break; |
169 | /* | 120 | /* |
170 | case WITHDRAW_REQUESTED: | 121 | case WITHDRAW_REQUESTED: |
171 | - intentWithdrawRequestedTimestampEpochMs = | 122 | + intentWithdrawRequestedEventMetric.eventReceived(); |
172 | - System.currentTimeMillis(); | ||
173 | - intentWithdrawRequestedRateMeter.mark(1); | ||
174 | break; | 123 | break; |
175 | */ | 124 | */ |
176 | case WITHDRAWN: | 125 | case WITHDRAWN: |
177 | - intentWithdrawnTimestampEpochMs = System.currentTimeMillis(); | 126 | + intentWithdrawnEventMetric.eventReceived(); |
178 | - intentWithdrawnRateMeter.mark(1); | ||
179 | break; | 127 | break; |
180 | default: | 128 | default: |
181 | break; | 129 | break; |
... | @@ -199,10 +147,6 @@ public class IntentMetrics implements IntentMetricsService, | ... | @@ -199,10 +147,6 @@ public class IntentMetrics implements IntentMetricsService, |
199 | */ | 147 | */ |
200 | private void clear() { | 148 | private void clear() { |
201 | synchronized (lastEvents) { | 149 | synchronized (lastEvents) { |
202 | - intentSubmittedTimestampEpochMs = 0; | ||
203 | - intentInstalledTimestampEpochMs = 0; | ||
204 | - intentWithdrawRequestedTimestampEpochMs = 0; | ||
205 | - intentWithdrawnTimestampEpochMs = 0; | ||
206 | lastEvents.clear(); | 150 | lastEvents.clear(); |
207 | } | 151 | } |
208 | } | 152 | } |
... | @@ -211,109 +155,32 @@ public class IntentMetrics implements IntentMetricsService, | ... | @@ -211,109 +155,32 @@ public class IntentMetrics implements IntentMetricsService, |
211 | * Registers the metrics. | 155 | * Registers the metrics. |
212 | */ | 156 | */ |
213 | private void registerMetrics() { | 157 | private void registerMetrics() { |
214 | - metricsComponent = metricsService.registerComponent(COMPONENT_NAME); | 158 | + intentSubmittedEventMetric = |
215 | - // | 159 | + new EventMetric(metricsService, COMPONENT_NAME, |
216 | - metricsFeatureSubmitted = | 160 | + FEATURE_SUBMITTED_NAME); |
217 | - metricsComponent.registerFeature(FEATURE_SUBMITTED_NAME); | 161 | + intentInstalledEventMetric = |
218 | - metricsFeatureInstalled = | 162 | + new EventMetric(metricsService, COMPONENT_NAME, |
219 | - metricsComponent.registerFeature(FEATURE_INSTALLED_NAME); | 163 | + FEATURE_INSTALLED_NAME); |
220 | - metricsFeatureWithdrawRequested = | 164 | + intentWithdrawRequestedEventMetric = |
221 | - metricsComponent.registerFeature(FEATURE_WITHDRAW_REQUESTED_NAME); | 165 | + new EventMetric(metricsService, COMPONENT_NAME, |
222 | - metricsFeatureWithdrawn = | 166 | + FEATURE_WITHDRAW_REQUESTED_NAME); |
223 | - metricsComponent.registerFeature(FEATURE_WITHDRAWN_NAME); | 167 | + intentWithdrawnEventMetric = |
224 | - // | 168 | + new EventMetric(metricsService, COMPONENT_NAME, |
225 | - intentSubmittedTimestampEpochMsGauge = | 169 | + FEATURE_WITHDRAWN_NAME); |
226 | - metricsService.registerMetric(metricsComponent, | 170 | + |
227 | - metricsFeatureSubmitted, | 171 | + intentSubmittedEventMetric.registerMetrics(); |
228 | - GAUGE_TIMESTAMP_NAME, | 172 | + intentInstalledEventMetric.registerMetrics(); |
229 | - new Gauge<Long>() { | 173 | + intentWithdrawRequestedEventMetric.registerMetrics(); |
230 | - @Override | 174 | + intentWithdrawnEventMetric.registerMetrics(); |
231 | - public Long getValue() { | ||
232 | - return intentSubmittedTimestampEpochMs; | ||
233 | - } | ||
234 | - }); | ||
235 | - // | ||
236 | - intentInstalledTimestampEpochMsGauge = | ||
237 | - metricsService.registerMetric(metricsComponent, | ||
238 | - metricsFeatureInstalled, | ||
239 | - GAUGE_TIMESTAMP_NAME, | ||
240 | - new Gauge<Long>() { | ||
241 | - @Override | ||
242 | - public Long getValue() { | ||
243 | - return intentInstalledTimestampEpochMs; | ||
244 | - } | ||
245 | - }); | ||
246 | - // | ||
247 | - intentWithdrawRequestedTimestampEpochMsGauge = | ||
248 | - metricsService.registerMetric(metricsComponent, | ||
249 | - metricsFeatureWithdrawRequested, | ||
250 | - GAUGE_TIMESTAMP_NAME, | ||
251 | - new Gauge<Long>() { | ||
252 | - @Override | ||
253 | - public Long getValue() { | ||
254 | - return intentWithdrawRequestedTimestampEpochMs; | ||
255 | - } | ||
256 | - }); | ||
257 | - // | ||
258 | - intentWithdrawnTimestampEpochMsGauge = | ||
259 | - metricsService.registerMetric(metricsComponent, | ||
260 | - metricsFeatureWithdrawn, | ||
261 | - GAUGE_TIMESTAMP_NAME, | ||
262 | - new Gauge<Long>() { | ||
263 | - @Override | ||
264 | - public Long getValue() { | ||
265 | - return intentWithdrawnTimestampEpochMs; | ||
266 | - } | ||
267 | - }); | ||
268 | - // | ||
269 | - intentSubmittedRateMeter = | ||
270 | - metricsService.createMeter(metricsComponent, | ||
271 | - metricsFeatureSubmitted, | ||
272 | - METER_RATE_NAME); | ||
273 | - // | ||
274 | - intentInstalledRateMeter = | ||
275 | - metricsService.createMeter(metricsComponent, | ||
276 | - metricsFeatureInstalled, | ||
277 | - METER_RATE_NAME); | ||
278 | - // | ||
279 | - intentWithdrawRequestedRateMeter = | ||
280 | - metricsService.createMeter(metricsComponent, | ||
281 | - metricsFeatureWithdrawRequested, | ||
282 | - METER_RATE_NAME); | ||
283 | - // | ||
284 | - intentWithdrawnRateMeter = | ||
285 | - metricsService.createMeter(metricsComponent, | ||
286 | - metricsFeatureWithdrawn, | ||
287 | - METER_RATE_NAME); | ||
288 | } | 175 | } |
289 | 176 | ||
290 | /** | 177 | /** |
291 | * Removes the metrics. | 178 | * Removes the metrics. |
292 | */ | 179 | */ |
293 | private void removeMetrics() { | 180 | private void removeMetrics() { |
294 | - metricsService.removeMetric(metricsComponent, | 181 | + intentSubmittedEventMetric.removeMetrics(); |
295 | - metricsFeatureSubmitted, | 182 | + intentInstalledEventMetric.removeMetrics(); |
296 | - GAUGE_TIMESTAMP_NAME); | 183 | + intentWithdrawRequestedEventMetric.removeMetrics(); |
297 | - metricsService.removeMetric(metricsComponent, | 184 | + intentWithdrawnEventMetric.removeMetrics(); |
298 | - metricsFeatureInstalled, | ||
299 | - GAUGE_TIMESTAMP_NAME); | ||
300 | - metricsService.removeMetric(metricsComponent, | ||
301 | - metricsFeatureWithdrawRequested, | ||
302 | - GAUGE_TIMESTAMP_NAME); | ||
303 | - metricsService.removeMetric(metricsComponent, | ||
304 | - metricsFeatureWithdrawn, | ||
305 | - GAUGE_TIMESTAMP_NAME); | ||
306 | - metricsService.removeMetric(metricsComponent, | ||
307 | - metricsFeatureSubmitted, | ||
308 | - METER_RATE_NAME); | ||
309 | - metricsService.removeMetric(metricsComponent, | ||
310 | - metricsFeatureInstalled, | ||
311 | - METER_RATE_NAME); | ||
312 | - metricsService.removeMetric(metricsComponent, | ||
313 | - metricsFeatureWithdrawRequested, | ||
314 | - METER_RATE_NAME); | ||
315 | - metricsService.removeMetric(metricsComponent, | ||
316 | - metricsFeatureWithdrawn, | ||
317 | - METER_RATE_NAME); | ||
318 | } | 185 | } |
319 | } | 186 | } | ... | ... |
1 | package org.onlab.onos.metrics.intent; | 1 | package org.onlab.onos.metrics.intent; |
2 | 2 | ||
3 | import java.util.List; | 3 | import java.util.List; |
4 | - | 4 | +import org.onlab.metrics.EventMetric; |
5 | -import com.codahale.metrics.Gauge; | ||
6 | -import com.codahale.metrics.Meter; | ||
7 | import org.onlab.onos.net.intent.IntentEvent; | 5 | import org.onlab.onos.net.intent.IntentEvent; |
8 | 6 | ||
9 | /** | 7 | /** |
... | @@ -18,68 +16,32 @@ public interface IntentMetricsService { | ... | @@ -18,68 +16,32 @@ public interface IntentMetricsService { |
18 | public List<IntentEvent> getEvents(); | 16 | public List<IntentEvent> getEvents(); |
19 | 17 | ||
20 | /** | 18 | /** |
21 | - * Gets the Metrics' Gauge for the intent SUBMITTED event timestamp | 19 | + * Gets the Event Metric for the intent SUBMITTED events. |
22 | - * (ms from the epoch). | ||
23 | * | 20 | * |
24 | - * @return the Metrics' Gauge for the intent SUBMITTED event timestamp | 21 | + * @return the Event Metric for the intent SUBMITTED events. |
25 | - * (ms from the epoch) | ||
26 | */ | 22 | */ |
27 | - public Gauge<Long> intentSubmittedTimestampEpochMsGauge(); | 23 | + public EventMetric intentSubmittedEventMetric(); |
28 | 24 | ||
29 | /** | 25 | /** |
30 | - * Gets the Metrics' Gauge for the intent INSTALLED event timestamp | 26 | + * Gets the Event Metric for the intent INSTALLED events. |
31 | - * (ms from the epoch). | ||
32 | * | 27 | * |
33 | - * @return the Metrics' Gauge for the intent INSTALLED event timestamp | 28 | + * @return the Event Metric for the intent INSTALLED events. |
34 | - * (ms from the epoch) | ||
35 | */ | 29 | */ |
36 | - public Gauge<Long> intentInstalledTimestampEpochMsGauge(); | 30 | + public EventMetric intentInstalledEventMetric(); |
37 | 31 | ||
38 | /** | 32 | /** |
39 | - * Gets the Metrics' Gauge for the intent WITHDRAW_REQUESTED event | 33 | + * Gets the Event Metric for the intent WITHDRAW_REQUESTED events. |
40 | - * timestamp (ms from the epoch). | ||
41 | * | 34 | * |
42 | * TODO: This intent event is not implemented yet. | 35 | * TODO: This intent event is not implemented yet. |
43 | * | 36 | * |
44 | - * @return the Metrics' Gauge for the intent WITHDRAW_REQUESTED event | 37 | + * @return the Event Metric for the intent WITHDRAW_REQUESTED events. |
45 | - * timestamp (ms from the epoch) | ||
46 | - */ | ||
47 | - public Gauge<Long> intentWithdrawRequestedTimestampEpochMsGauge(); | ||
48 | - | ||
49 | - /** | ||
50 | - * Gets the Metrics' Gauge for the intent WITHDRAWN event timestamp | ||
51 | - * (ms from the epoch). | ||
52 | - * | ||
53 | - * @return the Metrics' Gauge for the intent WITHDRAWN event timestamp | ||
54 | - * (ms from the epoch) | ||
55 | - */ | ||
56 | - public Gauge<Long> intentWithdrawnTimestampEpochMsGauge(); | ||
57 | - | ||
58 | - /** | ||
59 | - * Gets the Metrics' Meter for the submitted intents event rate. | ||
60 | - * | ||
61 | - * @return the Metrics' Meter for the submitted intents event rate | ||
62 | - */ | ||
63 | - public Meter intentSubmittedRateMeter(); | ||
64 | - | ||
65 | - /** | ||
66 | - * Gets the Metrics' Meter for the installed intents event rate. | ||
67 | - * | ||
68 | - * @return the Metrics' Meter for the installed intent event rate | ||
69 | - */ | ||
70 | - public Meter intentInstalledRateMeter(); | ||
71 | - | ||
72 | - /** | ||
73 | - * Gets the Metrics' Meter for the withdraw requested intents event rate. | ||
74 | - * | ||
75 | - * @return the Metrics' Meter for the withdraw requested intents event rate | ||
76 | */ | 38 | */ |
77 | - public Meter intentWithdrawRequestedRateMeter(); | 39 | + public EventMetric intentWithdrawRequestedEventMetric(); |
78 | 40 | ||
79 | /** | 41 | /** |
80 | - * Gets the Metrics' Meter for the withdraw completed intents event rate. | 42 | + * Gets the Event Metric for the intent WITHDRAWN events. |
81 | * | 43 | * |
82 | - * @return the Metrics' Meter for the withdraw completed intents event rate | 44 | + * @return the Event Metric for the intent WITHDRAWN events. |
83 | */ | 45 | */ |
84 | - public Meter intentWithdrawnRateMeter(); | 46 | + public EventMetric intentWithdrawnEventMetric(); |
85 | } | 47 | } | ... | ... |
... | @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.JsonNode; | ... | @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.JsonNode; |
11 | import com.fasterxml.jackson.databind.ObjectMapper; | 11 | import com.fasterxml.jackson.databind.ObjectMapper; |
12 | import com.fasterxml.jackson.databind.node.ObjectNode; | 12 | import com.fasterxml.jackson.databind.node.ObjectNode; |
13 | import org.apache.karaf.shell.commands.Command; | 13 | import org.apache.karaf.shell.commands.Command; |
14 | +import org.onlab.metrics.EventMetric; | ||
14 | import org.onlab.onos.cli.AbstractShellCommand; | 15 | import org.onlab.onos.cli.AbstractShellCommand; |
15 | import org.onlab.onos.metrics.intent.IntentMetricsService; | 16 | import org.onlab.onos.metrics.intent.IntentMetricsService; |
16 | 17 | ||
... | @@ -29,8 +30,6 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand { | ... | @@ -29,8 +30,6 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand { |
29 | @Override | 30 | @Override |
30 | protected void execute() { | 31 | protected void execute() { |
31 | IntentMetricsService service = get(IntentMetricsService.class); | 32 | IntentMetricsService service = get(IntentMetricsService.class); |
32 | - Gauge<Long> gauge; | ||
33 | - Meter meter; | ||
34 | 33 | ||
35 | if (outputJson()) { | 34 | if (outputJson()) { |
36 | ObjectMapper mapper = new ObjectMapper() | 35 | ObjectMapper mapper = new ObjectMapper() |
... | @@ -38,46 +37,46 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand { | ... | @@ -38,46 +37,46 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand { |
38 | TimeUnit.MILLISECONDS, | 37 | TimeUnit.MILLISECONDS, |
39 | false)); | 38 | false)); |
40 | ObjectNode result = mapper.createObjectNode(); | 39 | ObjectNode result = mapper.createObjectNode(); |
41 | - // | 40 | + result = json(mapper, result, "intentSubmitted", |
42 | - gauge = service.intentSubmittedTimestampEpochMsGauge(); | 41 | + service.intentSubmittedEventMetric()); |
43 | - result.put("intentSubmittedTimestamp", json(mapper, gauge)); | 42 | + result = json(mapper, result, "intentInstalled", |
44 | - gauge = service.intentInstalledTimestampEpochMsGauge(); | 43 | + service.intentInstalledEventMetric()); |
45 | - result.put("intentInstalledTimestamp", json(mapper, gauge)); | 44 | + result = json(mapper, result, "intentWithdrawRequested", |
46 | - gauge = service.intentWithdrawRequestedTimestampEpochMsGauge(); | 45 | + service.intentWithdrawRequestedEventMetric()); |
47 | - result.put("intentWithdrawRequestedTimestamp", | 46 | + result = json(mapper, result, "intentWithdrawn", |
48 | - json(mapper, gauge)); | 47 | + service.intentWithdrawnEventMetric()); |
49 | - gauge = service.intentWithdrawnTimestampEpochMsGauge(); | ||
50 | - result.put("intentWithdrawnTimestamp", json(mapper, gauge)); | ||
51 | - // | ||
52 | - meter = service.intentSubmittedRateMeter(); | ||
53 | - result.put("intentSubmittedRate", json(mapper, meter)); | ||
54 | - meter = service.intentInstalledRateMeter(); | ||
55 | - result.put("intentInstalledRate", json(mapper, meter)); | ||
56 | - meter = service.intentWithdrawRequestedRateMeter(); | ||
57 | - result.put("intentWithdrawRequestedRate", json(mapper, meter)); | ||
58 | - meter = service.intentWithdrawnRateMeter(); | ||
59 | - result.put("intentWithdrawnRate", json(mapper, meter)); | ||
60 | - // | ||
61 | print("%s", result); | 48 | print("%s", result); |
62 | } else { | 49 | } else { |
63 | - gauge = service.intentSubmittedTimestampEpochMsGauge(); | 50 | + printEventMetric("Submitted", |
64 | - printGauge("Submitted", gauge); | 51 | + service.intentSubmittedEventMetric()); |
65 | - gauge = service.intentInstalledTimestampEpochMsGauge(); | 52 | + printEventMetric("Installed", |
66 | - printGauge("Installed", gauge); | 53 | + service.intentInstalledEventMetric()); |
67 | - gauge = service.intentWithdrawRequestedTimestampEpochMsGauge(); | 54 | + printEventMetric("Withdraw Requested", |
68 | - printGauge("Withdraw Requested", gauge); | 55 | + service.intentWithdrawRequestedEventMetric()); |
69 | - gauge = service.intentWithdrawnTimestampEpochMsGauge(); | 56 | + printEventMetric("Withdrawn", |
70 | - printGauge("Withdrawn", gauge); | 57 | + service.intentWithdrawnEventMetric()); |
71 | - // | 58 | + } |
72 | - meter = service.intentSubmittedRateMeter(); | ||
73 | - printMeter("Submitted", meter); | ||
74 | - meter = service.intentInstalledRateMeter(); | ||
75 | - printMeter("Installed", meter); | ||
76 | - meter = service.intentWithdrawRequestedRateMeter(); | ||
77 | - printMeter("Withdraw Requested", meter); | ||
78 | - meter = service.intentWithdrawnRateMeter(); | ||
79 | - printMeter("Withdrawn", meter); | ||
80 | } | 59 | } |
60 | + | ||
61 | + /** | ||
62 | + * Produces JSON node for an Event Metric. | ||
63 | + * | ||
64 | + * @param mapper the JSON object mapper to use | ||
65 | + * @param objectNode the JSON object node to use | ||
66 | + * @param propertyPrefix the property prefix to use | ||
67 | + * @param eventMetric the Event Metric with the data | ||
68 | + * @return JSON object node for the Event Metric | ||
69 | + */ | ||
70 | + private ObjectNode json(ObjectMapper mapper, ObjectNode objectNode, | ||
71 | + String propertyPrefix, EventMetric eventMetric) { | ||
72 | + String gaugeName = propertyPrefix + "Timestamp"; | ||
73 | + String meterName = propertyPrefix + "Rate"; | ||
74 | + Gauge<Long> gauge = eventMetric.lastEventTimestampGauge(); | ||
75 | + Meter meter = eventMetric.eventRateMeter(); | ||
76 | + | ||
77 | + objectNode.put(gaugeName, json(mapper, gauge)); | ||
78 | + objectNode.put(meterName, json(mapper, meter)); | ||
79 | + return objectNode; | ||
81 | } | 80 | } |
82 | 81 | ||
83 | /** | 82 | /** |
... | @@ -94,8 +93,8 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand { | ... | @@ -94,8 +93,8 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand { |
94 | // | 93 | // |
95 | try { | 94 | try { |
96 | final String objectJson = mapper.writeValueAsString(object); | 95 | final String objectJson = mapper.writeValueAsString(object); |
97 | - JsonNode objectNode = mapper.readTree(objectJson); | 96 | + JsonNode jsonNode = mapper.readTree(objectJson); |
98 | - return objectNode; | 97 | + return jsonNode; |
99 | } catch (JsonProcessingException e) { | 98 | } catch (JsonProcessingException e) { |
100 | log.error("Error writing value as JSON string", e); | 99 | log.error("Error writing value as JSON string", e); |
101 | } catch (IOException e) { | 100 | } catch (IOException e) { |
... | @@ -105,24 +104,22 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand { | ... | @@ -105,24 +104,22 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand { |
105 | } | 104 | } |
106 | 105 | ||
107 | /** | 106 | /** |
108 | - * Prints a Gauge. | 107 | + * Prints an Event Metric. |
109 | * | 108 | * |
110 | * @param operationStr the string with the intent operation to print | 109 | * @param operationStr the string with the intent operation to print |
111 | - * @param gauge the Gauge to print | 110 | + * @param eventMetric the Event Metric to print |
112 | */ | 111 | */ |
113 | - private void printGauge(String operationStr, Gauge<Long> gauge) { | 112 | + private void printEventMetric(String operationStr, |
114 | - print(FORMAT_GAUGE, operationStr, gauge.getValue()); | 113 | + EventMetric eventMetric) { |
115 | - } | 114 | + Gauge<Long> gauge = eventMetric.lastEventTimestampGauge(); |
116 | - | 115 | + Meter meter = eventMetric.eventRateMeter(); |
117 | - /** | ||
118 | - * Prints a Meter. | ||
119 | - * | ||
120 | - * @param operationStr the string with the intent operation to print | ||
121 | - * @param meter the Meter to print | ||
122 | - */ | ||
123 | - private void printMeter(String operationStr, Meter meter) { | ||
124 | TimeUnit rateUnit = TimeUnit.SECONDS; | 116 | TimeUnit rateUnit = TimeUnit.SECONDS; |
125 | double rateFactor = rateUnit.toSeconds(1); | 117 | double rateFactor = rateUnit.toSeconds(1); |
118 | + | ||
119 | + // Print the Gauge | ||
120 | + print(FORMAT_GAUGE, operationStr, gauge.getValue()); | ||
121 | + | ||
122 | + // Print the Meter | ||
126 | print(FORMAT_METER, operationStr, meter.getCount(), | 123 | print(FORMAT_METER, operationStr, meter.getCount(), |
127 | meter.getMeanRate() * rateFactor, | 124 | meter.getMeanRate() * rateFactor, |
128 | meter.getOneMinuteRate() * rateFactor, | 125 | meter.getOneMinuteRate() * rateFactor, | ... | ... |
... | @@ -5,8 +5,6 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -5,8 +5,6 @@ import static org.slf4j.LoggerFactory.getLogger; |
5 | import java.util.LinkedList; | 5 | import java.util.LinkedList; |
6 | import java.util.List; | 6 | import java.util.List; |
7 | 7 | ||
8 | -import com.codahale.metrics.Gauge; | ||
9 | -import com.codahale.metrics.Meter; | ||
10 | import com.google.common.collect.ImmutableList; | 8 | import com.google.common.collect.ImmutableList; |
11 | import org.apache.felix.scr.annotations.Activate; | 9 | import org.apache.felix.scr.annotations.Activate; |
12 | import org.apache.felix.scr.annotations.Component; | 10 | import org.apache.felix.scr.annotations.Component; |
... | @@ -14,8 +12,7 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -14,8 +12,7 @@ import org.apache.felix.scr.annotations.Deactivate; |
14 | import org.apache.felix.scr.annotations.Reference; | 12 | import org.apache.felix.scr.annotations.Reference; |
15 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 13 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
16 | import org.apache.felix.scr.annotations.Service; | 14 | import org.apache.felix.scr.annotations.Service; |
17 | -import org.onlab.metrics.MetricsComponent; | 15 | +import org.onlab.metrics.EventMetric; |
18 | -import org.onlab.metrics.MetricsFeature; | ||
19 | import org.onlab.metrics.MetricsService; | 16 | import org.onlab.metrics.MetricsService; |
20 | import org.onlab.onos.event.Event; | 17 | import org.onlab.onos.event.Event; |
21 | import org.onlab.onos.net.device.DeviceEvent; | 18 | import org.onlab.onos.net.device.DeviceEvent; |
... | @@ -48,6 +45,8 @@ public class TopologyMetrics implements TopologyMetricsService { | ... | @@ -48,6 +45,8 @@ public class TopologyMetrics implements TopologyMetricsService { |
48 | protected LinkService linkService; | 45 | protected LinkService linkService; |
49 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 46 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
50 | protected TopologyService topologyService; | 47 | protected TopologyService topologyService; |
48 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
49 | + protected MetricsService metricsService; | ||
51 | 50 | ||
52 | private LinkedList<Event> lastEvents = new LinkedList<>(); | 51 | private LinkedList<Event> lastEvents = new LinkedList<>(); |
53 | private static final int LAST_EVENTS_MAX_N = 100; | 52 | private static final int LAST_EVENTS_MAX_N = 100; |
... | @@ -61,22 +60,22 @@ public class TopologyMetrics implements TopologyMetricsService { | ... | @@ -61,22 +60,22 @@ public class TopologyMetrics implements TopologyMetricsService { |
61 | // | 60 | // |
62 | // Metrics | 61 | // Metrics |
63 | // | 62 | // |
64 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
65 | - protected MetricsService metricsService; | ||
66 | - // | ||
67 | private static final String COMPONENT_NAME = "Topology"; | 63 | private static final String COMPONENT_NAME = "Topology"; |
68 | - private static final String FEATURE_NAME = "EventNotification"; | 64 | + private static final String FEATURE_DEVICE_NAME = "DeviceEvent"; |
69 | - private static final String GAUGE_NAME = "LastEventTimestamp.EpochMs"; | 65 | + private static final String FEATURE_HOST_NAME = "HostEvent"; |
70 | - private static final String METER_NAME = "EventRate"; | 66 | + private static final String FEATURE_LINK_NAME = "LinkEvent"; |
67 | + private static final String FEATURE_GRAPH_NAME = "GraphEvent"; | ||
71 | // | 68 | // |
72 | - private MetricsComponent metricsComponent; | 69 | + // Event metrics: |
73 | - private MetricsFeature metricsFeatureEventNotification; | 70 | + // - Device events |
71 | + // - Host events | ||
72 | + // - Link events | ||
73 | + // - Topology Graph events | ||
74 | // | 74 | // |
75 | - // Timestamp of the last Topology event (ms from the Epoch) | 75 | + private EventMetric topologyDeviceEventMetric; |
76 | - private volatile long lastEventTimestampEpochMs = 0; | 76 | + private EventMetric topologyHostEventMetric; |
77 | - private Gauge<Long> lastEventTimestampEpochMsGauge; | 77 | + private EventMetric topologyLinkEventMetric; |
78 | - // Rate of the Topology events published to the Topology listeners | 78 | + private EventMetric topologyGraphEventMetric; |
79 | - private Meter eventRateMeter; | ||
80 | 79 | ||
81 | @Activate | 80 | @Activate |
82 | protected void activate() { | 81 | protected void activate() { |
... | @@ -113,27 +112,34 @@ public class TopologyMetrics implements TopologyMetricsService { | ... | @@ -113,27 +112,34 @@ public class TopologyMetrics implements TopologyMetricsService { |
113 | } | 112 | } |
114 | 113 | ||
115 | @Override | 114 | @Override |
116 | - public Gauge<Long> lastEventTimestampEpochMsGauge() { | 115 | + public EventMetric topologyDeviceEventMetric() { |
117 | - return lastEventTimestampEpochMsGauge; | 116 | + return topologyDeviceEventMetric; |
118 | } | 117 | } |
119 | 118 | ||
120 | @Override | 119 | @Override |
121 | - public Meter eventRateMeter() { | 120 | + public EventMetric topologyHostEventMetric() { |
122 | - return eventRateMeter; | 121 | + return topologyHostEventMetric; |
122 | + } | ||
123 | + | ||
124 | + @Override | ||
125 | + public EventMetric topologyLinkEventMetric() { | ||
126 | + return topologyLinkEventMetric; | ||
127 | + } | ||
128 | + | ||
129 | + @Override | ||
130 | + public EventMetric topologyGraphEventMetric() { | ||
131 | + return topologyGraphEventMetric; | ||
123 | } | 132 | } |
124 | 133 | ||
125 | /** | 134 | /** |
126 | * Records an event. | 135 | * Records an event. |
127 | * | 136 | * |
128 | * @param event the event to record | 137 | * @param event the event to record |
129 | - * @param updateEventRateMeter if true, update the Event Rate Meter | 138 | + * @param eventMetric the Event Metric to use |
130 | */ | 139 | */ |
131 | - private void recordEvent(Event event, boolean updateEventRateMeter) { | 140 | + private void recordEvent(Event event, EventMetric eventMetric) { |
132 | synchronized (lastEvents) { | 141 | synchronized (lastEvents) { |
133 | - lastEventTimestampEpochMs = System.currentTimeMillis(); | 142 | + eventMetric.eventReceived(); |
134 | - if (updateEventRateMeter) { | ||
135 | - eventRateMeter.mark(1); | ||
136 | - } | ||
137 | 143 | ||
138 | // | 144 | // |
139 | // Keep only the last N events, where N = LAST_EVENTS_MAX_N | 145 | // Keep only the last N events, where N = LAST_EVENTS_MAX_N |
... | @@ -151,7 +157,7 @@ public class TopologyMetrics implements TopologyMetricsService { | ... | @@ -151,7 +157,7 @@ public class TopologyMetrics implements TopologyMetricsService { |
151 | private class InnerDeviceListener implements DeviceListener { | 157 | private class InnerDeviceListener implements DeviceListener { |
152 | @Override | 158 | @Override |
153 | public void event(DeviceEvent event) { | 159 | public void event(DeviceEvent event) { |
154 | - recordEvent(event, true); | 160 | + recordEvent(event, topologyDeviceEventMetric); |
155 | log.debug("Device Event: time = {} type = {} event = {}", | 161 | log.debug("Device Event: time = {} type = {} event = {}", |
156 | event.time(), event.type(), event); | 162 | event.time(), event.type(), event); |
157 | } | 163 | } |
... | @@ -163,7 +169,7 @@ public class TopologyMetrics implements TopologyMetricsService { | ... | @@ -163,7 +169,7 @@ public class TopologyMetrics implements TopologyMetricsService { |
163 | private class InnerHostListener implements HostListener { | 169 | private class InnerHostListener implements HostListener { |
164 | @Override | 170 | @Override |
165 | public void event(HostEvent event) { | 171 | public void event(HostEvent event) { |
166 | - recordEvent(event, true); | 172 | + recordEvent(event, topologyHostEventMetric); |
167 | log.debug("Host Event: time = {} type = {} event = {}", | 173 | log.debug("Host Event: time = {} type = {} event = {}", |
168 | event.time(), event.type(), event); | 174 | event.time(), event.type(), event); |
169 | } | 175 | } |
... | @@ -175,7 +181,7 @@ public class TopologyMetrics implements TopologyMetricsService { | ... | @@ -175,7 +181,7 @@ public class TopologyMetrics implements TopologyMetricsService { |
175 | private class InnerLinkListener implements LinkListener { | 181 | private class InnerLinkListener implements LinkListener { |
176 | @Override | 182 | @Override |
177 | public void event(LinkEvent event) { | 183 | public void event(LinkEvent event) { |
178 | - recordEvent(event, true); | 184 | + recordEvent(event, topologyLinkEventMetric); |
179 | log.debug("Link Event: time = {} type = {} event = {}", | 185 | log.debug("Link Event: time = {} type = {} event = {}", |
180 | event.time(), event.type(), event); | 186 | event.time(), event.type(), event); |
181 | } | 187 | } |
... | @@ -187,11 +193,7 @@ public class TopologyMetrics implements TopologyMetricsService { | ... | @@ -187,11 +193,7 @@ public class TopologyMetrics implements TopologyMetricsService { |
187 | private class InnerTopologyListener implements TopologyListener { | 193 | private class InnerTopologyListener implements TopologyListener { |
188 | @Override | 194 | @Override |
189 | public void event(TopologyEvent event) { | 195 | public void event(TopologyEvent event) { |
190 | - // | 196 | + recordEvent(event, topologyGraphEventMetric); |
191 | - // NOTE: Don't update the eventRateMeter, because the real | ||
192 | - // events are already captured/counted. | ||
193 | - // | ||
194 | - recordEvent(event, false); | ||
195 | log.debug("Topology Event: time = {} type = {} event = {}", | 197 | log.debug("Topology Event: time = {} type = {} event = {}", |
196 | event.time(), event.type(), event); | 198 | event.time(), event.type(), event); |
197 | for (Event reason : event.reasons()) { | 199 | for (Event reason : event.reasons()) { |
... | @@ -206,7 +208,6 @@ public class TopologyMetrics implements TopologyMetricsService { | ... | @@ -206,7 +208,6 @@ public class TopologyMetrics implements TopologyMetricsService { |
206 | */ | 208 | */ |
207 | private void clear() { | 209 | private void clear() { |
208 | synchronized (lastEvents) { | 210 | synchronized (lastEvents) { |
209 | - lastEventTimestampEpochMs = 0; | ||
210 | lastEvents.clear(); | 211 | lastEvents.clear(); |
211 | } | 212 | } |
212 | } | 213 | } |
... | @@ -215,35 +216,32 @@ public class TopologyMetrics implements TopologyMetricsService { | ... | @@ -215,35 +216,32 @@ public class TopologyMetrics implements TopologyMetricsService { |
215 | * Registers the metrics. | 216 | * Registers the metrics. |
216 | */ | 217 | */ |
217 | private void registerMetrics() { | 218 | private void registerMetrics() { |
218 | - metricsComponent = metricsService.registerComponent(COMPONENT_NAME); | 219 | + topologyDeviceEventMetric = |
219 | - metricsFeatureEventNotification = | 220 | + new EventMetric(metricsService, COMPONENT_NAME, |
220 | - metricsComponent.registerFeature(FEATURE_NAME); | 221 | + FEATURE_DEVICE_NAME); |
221 | - lastEventTimestampEpochMsGauge = | 222 | + topologyHostEventMetric = |
222 | - metricsService.registerMetric(metricsComponent, | 223 | + new EventMetric(metricsService, COMPONENT_NAME, |
223 | - metricsFeatureEventNotification, | 224 | + FEATURE_HOST_NAME); |
224 | - GAUGE_NAME, | 225 | + topologyLinkEventMetric = |
225 | - new Gauge<Long>() { | 226 | + new EventMetric(metricsService, COMPONENT_NAME, |
226 | - @Override | 227 | + FEATURE_LINK_NAME); |
227 | - public Long getValue() { | 228 | + topologyGraphEventMetric = |
228 | - return lastEventTimestampEpochMs; | 229 | + new EventMetric(metricsService, COMPONENT_NAME, |
229 | - } | 230 | + FEATURE_GRAPH_NAME); |
230 | - }); | 231 | + |
231 | - eventRateMeter = | 232 | + topologyDeviceEventMetric.registerMetrics(); |
232 | - metricsService.createMeter(metricsComponent, | 233 | + topologyHostEventMetric.registerMetrics(); |
233 | - metricsFeatureEventNotification, | 234 | + topologyLinkEventMetric.registerMetrics(); |
234 | - METER_NAME); | 235 | + topologyGraphEventMetric.registerMetrics(); |
235 | - | ||
236 | } | 236 | } |
237 | 237 | ||
238 | /** | 238 | /** |
239 | * Removes the metrics. | 239 | * Removes the metrics. |
240 | */ | 240 | */ |
241 | private void removeMetrics() { | 241 | private void removeMetrics() { |
242 | - metricsService.removeMetric(metricsComponent, | 242 | + topologyDeviceEventMetric.removeMetrics(); |
243 | - metricsFeatureEventNotification, | 243 | + topologyHostEventMetric.removeMetrics(); |
244 | - GAUGE_NAME); | 244 | + topologyLinkEventMetric.removeMetrics(); |
245 | - metricsService.removeMetric(metricsComponent, | 245 | + topologyGraphEventMetric.removeMetrics(); |
246 | - metricsFeatureEventNotification, | ||
247 | - METER_NAME); | ||
248 | } | 246 | } |
249 | } | 247 | } | ... | ... |
1 | package org.onlab.onos.metrics.topology; | 1 | package org.onlab.onos.metrics.topology; |
2 | 2 | ||
3 | import java.util.List; | 3 | import java.util.List; |
4 | - | 4 | +import org.onlab.metrics.EventMetric; |
5 | -import com.codahale.metrics.Gauge; | ||
6 | -import com.codahale.metrics.Meter; | ||
7 | import org.onlab.onos.event.Event; | 5 | import org.onlab.onos.event.Event; |
8 | 6 | ||
9 | /** | 7 | /** |
... | @@ -18,18 +16,30 @@ public interface TopologyMetricsService { | ... | @@ -18,18 +16,30 @@ public interface TopologyMetricsService { |
18 | public List<Event> getEvents(); | 16 | public List<Event> getEvents(); |
19 | 17 | ||
20 | /** | 18 | /** |
21 | - * Gets the Metrics' Gauge for the last topology event timestamp | 19 | + * Gets the Event Metric for the Device Events. |
22 | - * (ms from the epoch). | 20 | + * |
21 | + * @return the Event Metric for the Device Events. | ||
22 | + */ | ||
23 | + public EventMetric topologyDeviceEventMetric(); | ||
24 | + | ||
25 | + /** | ||
26 | + * Gets the Event Metric for the Host Events. | ||
27 | + * | ||
28 | + * @return the Event Metric for the Host Events. | ||
29 | + */ | ||
30 | + public EventMetric topologyHostEventMetric(); | ||
31 | + | ||
32 | + /** | ||
33 | + * Gets the Event Metric for the Link Events. | ||
23 | * | 34 | * |
24 | - * @return the Metrics' Gauge for the last topology event timestamp | 35 | + * @return the Event Metric for the Link Events. |
25 | - * (ms from the epoch) | ||
26 | */ | 36 | */ |
27 | - public Gauge<Long> lastEventTimestampEpochMsGauge(); | 37 | + public EventMetric topologyLinkEventMetric(); |
28 | 38 | ||
29 | /** | 39 | /** |
30 | - * Gets the Metrics' Meter for the topology events rate. | 40 | + * Gets the Event Metric for the Topology Graph Events. |
31 | * | 41 | * |
32 | - * @return the Metrics' Meter for the topology events rate | 42 | + * @return the Event Metric for the Topology Graph Events. |
33 | */ | 43 | */ |
34 | - public Meter eventRateMeter(); | 44 | + public EventMetric topologyGraphEventMetric(); |
35 | } | 45 | } | ... | ... |
... | @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.JsonNode; | ... | @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.JsonNode; |
11 | import com.fasterxml.jackson.databind.ObjectMapper; | 11 | import com.fasterxml.jackson.databind.ObjectMapper; |
12 | import com.fasterxml.jackson.databind.node.ObjectNode; | 12 | import com.fasterxml.jackson.databind.node.ObjectNode; |
13 | import org.apache.karaf.shell.commands.Command; | 13 | import org.apache.karaf.shell.commands.Command; |
14 | +import org.onlab.metrics.EventMetric; | ||
14 | import org.onlab.onos.cli.AbstractShellCommand; | 15 | import org.onlab.onos.cli.AbstractShellCommand; |
15 | import org.onlab.onos.metrics.topology.TopologyMetricsService; | 16 | import org.onlab.onos.metrics.topology.TopologyMetricsService; |
16 | 17 | ||
... | @@ -22,15 +23,13 @@ import org.onlab.onos.metrics.topology.TopologyMetricsService; | ... | @@ -22,15 +23,13 @@ import org.onlab.onos.metrics.topology.TopologyMetricsService; |
22 | public class TopologyEventsMetricsCommand extends AbstractShellCommand { | 23 | public class TopologyEventsMetricsCommand extends AbstractShellCommand { |
23 | 24 | ||
24 | private static final String FORMAT_GAUGE = | 25 | private static final String FORMAT_GAUGE = |
25 | - "Last Topology Event Timestamp (ms from epoch)=%d"; | 26 | + "Topology %s Event Timestamp (ms from epoch)=%d"; |
26 | private static final String FORMAT_METER = | 27 | private static final String FORMAT_METER = |
27 | - "Topology Events count=%d rate(events/sec) mean=%f m1=%f m5=%f m15=%f"; | 28 | + "Topology %s Events count=%d rate(events/sec) mean=%f m1=%f m5=%f m15=%f"; |
28 | 29 | ||
29 | @Override | 30 | @Override |
30 | protected void execute() { | 31 | protected void execute() { |
31 | TopologyMetricsService service = get(TopologyMetricsService.class); | 32 | TopologyMetricsService service = get(TopologyMetricsService.class); |
32 | - Gauge<Long> gauge = service.lastEventTimestampEpochMsGauge(); | ||
33 | - Meter meter = service.eventRateMeter(); | ||
34 | 33 | ||
35 | if (outputJson()) { | 34 | if (outputJson()) { |
36 | ObjectMapper mapper = new ObjectMapper() | 35 | ObjectMapper mapper = new ObjectMapper() |
... | @@ -38,32 +37,89 @@ public class TopologyEventsMetricsCommand extends AbstractShellCommand { | ... | @@ -38,32 +37,89 @@ public class TopologyEventsMetricsCommand extends AbstractShellCommand { |
38 | TimeUnit.MILLISECONDS, | 37 | TimeUnit.MILLISECONDS, |
39 | false)); | 38 | false)); |
40 | ObjectNode result = mapper.createObjectNode(); | 39 | ObjectNode result = mapper.createObjectNode(); |
41 | - try { | 40 | + result = json(mapper, result, "topologyDeviceEvent", |
41 | + service.topologyDeviceEventMetric()); | ||
42 | + result = json(mapper, result, "topologyHostEvent", | ||
43 | + service.topologyHostEventMetric()); | ||
44 | + result = json(mapper, result, "topologyLinkEvent", | ||
45 | + service.topologyLinkEventMetric()); | ||
46 | + result = json(mapper, result, "topologyGraphEvent", | ||
47 | + service.topologyGraphEventMetric()); | ||
48 | + print("%s", result); | ||
49 | + } else { | ||
50 | + printEventMetric("Device", service.topologyDeviceEventMetric()); | ||
51 | + printEventMetric("Host", service.topologyHostEventMetric()); | ||
52 | + printEventMetric("Link", service.topologyLinkEventMetric()); | ||
53 | + printEventMetric("Graph", service.topologyGraphEventMetric()); | ||
54 | + } | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * Produces JSON node for an Event Metric. | ||
59 | + * | ||
60 | + * @param mapper the JSON object mapper to use | ||
61 | + * @param objectNode the JSON object node to use | ||
62 | + * @param propertyPrefix the property prefix to use | ||
63 | + * @param eventMetric the Event Metric with the data | ||
64 | + * @return JSON object node for the Event Metric | ||
65 | + */ | ||
66 | + private ObjectNode json(ObjectMapper mapper, ObjectNode objectNode, | ||
67 | + String propertyPrefix, EventMetric eventMetric) { | ||
68 | + String gaugeName = propertyPrefix + "Timestamp"; | ||
69 | + String meterName = propertyPrefix + "Rate"; | ||
70 | + Gauge<Long> gauge = eventMetric.lastEventTimestampGauge(); | ||
71 | + Meter meter = eventMetric.eventRateMeter(); | ||
72 | + | ||
73 | + objectNode.put(gaugeName, json(mapper, gauge)); | ||
74 | + objectNode.put(meterName, json(mapper, meter)); | ||
75 | + return objectNode; | ||
76 | + } | ||
77 | + | ||
78 | + /** | ||
79 | + * Produces JSON node for an Object. | ||
80 | + * | ||
81 | + * @param mapper the JSON object mapper to use | ||
82 | + * @param object the Object with the data | ||
83 | + * @return JSON node for the Object | ||
84 | + */ | ||
85 | + private JsonNode json(ObjectMapper mapper, Object object) { | ||
42 | // | 86 | // |
43 | // NOTE: The API for custom serializers is incomplete, | 87 | // NOTE: The API for custom serializers is incomplete, |
44 | // hence we have to parse the JSON string to create JsonNode. | 88 | // hence we have to parse the JSON string to create JsonNode. |
45 | // | 89 | // |
46 | - final String gaugeJson = mapper.writeValueAsString(gauge); | 90 | + try { |
47 | - final String meterJson = mapper.writeValueAsString(meter); | 91 | + final String objectJson = mapper.writeValueAsString(object); |
48 | - JsonNode gaugeNode = mapper.readTree(gaugeJson); | 92 | + JsonNode jsonNode = mapper.readTree(objectJson); |
49 | - JsonNode meterNode = mapper.readTree(meterJson); | 93 | + return jsonNode; |
50 | - result.put("lastTopologyEventTimestamp", gaugeNode); | ||
51 | - result.put("topologyEventRate", meterNode); | ||
52 | } catch (JsonProcessingException e) { | 94 | } catch (JsonProcessingException e) { |
53 | log.error("Error writing value as JSON string", e); | 95 | log.error("Error writing value as JSON string", e); |
54 | } catch (IOException e) { | 96 | } catch (IOException e) { |
55 | log.error("Error writing value as JSON string", e); | 97 | log.error("Error writing value as JSON string", e); |
56 | } | 98 | } |
57 | - print("%s", result); | 99 | + return null; |
58 | - } else { | 100 | + } |
101 | + | ||
102 | + /** | ||
103 | + * Prints an Event Metric. | ||
104 | + * | ||
105 | + * @param operationStr the string with the intent operation to print | ||
106 | + * @param eventMetric the Event Metric to print | ||
107 | + */ | ||
108 | + private void printEventMetric(String operationStr, | ||
109 | + EventMetric eventMetric) { | ||
110 | + Gauge<Long> gauge = eventMetric.lastEventTimestampGauge(); | ||
111 | + Meter meter = eventMetric.eventRateMeter(); | ||
59 | TimeUnit rateUnit = TimeUnit.SECONDS; | 112 | TimeUnit rateUnit = TimeUnit.SECONDS; |
60 | double rateFactor = rateUnit.toSeconds(1); | 113 | double rateFactor = rateUnit.toSeconds(1); |
61 | - print(FORMAT_GAUGE, gauge.getValue()); | 114 | + |
62 | - print(FORMAT_METER, meter.getCount(), | 115 | + // Print the Gauge |
116 | + print(FORMAT_GAUGE, operationStr, gauge.getValue()); | ||
117 | + | ||
118 | + // Print the Meter | ||
119 | + print(FORMAT_METER, operationStr, meter.getCount(), | ||
63 | meter.getMeanRate() * rateFactor, | 120 | meter.getMeanRate() * rateFactor, |
64 | meter.getOneMinuteRate() * rateFactor, | 121 | meter.getOneMinuteRate() * rateFactor, |
65 | meter.getFiveMinuteRate() * rateFactor, | 122 | meter.getFiveMinuteRate() * rateFactor, |
66 | meter.getFifteenMinuteRate() * rateFactor); | 123 | meter.getFifteenMinuteRate() * rateFactor); |
67 | } | 124 | } |
68 | - } | ||
69 | } | 125 | } | ... | ... |
apps/optical/src/main/java/org/onlab/onos/optical/provisioner/OpticalPathProvisioner.java
0 → 100644
1 | +package org.onlab.onos.optical.provisioner; | ||
2 | + | ||
3 | +import java.util.ArrayList; | ||
4 | +import java.util.HashMap; | ||
5 | +import java.util.Iterator; | ||
6 | +import java.util.Map; | ||
7 | +import java.util.Map.Entry; | ||
8 | +import java.util.Set; | ||
9 | + | ||
10 | +import org.apache.felix.scr.annotations.Activate; | ||
11 | +import org.apache.felix.scr.annotations.Component; | ||
12 | +import org.apache.felix.scr.annotations.Deactivate; | ||
13 | +import org.apache.felix.scr.annotations.Reference; | ||
14 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
15 | +import org.onlab.onos.ApplicationId; | ||
16 | +import org.onlab.onos.CoreService; | ||
17 | +import org.onlab.onos.net.ConnectPoint; | ||
18 | +import org.onlab.onos.net.Link; | ||
19 | +import org.onlab.onos.net.Path; | ||
20 | +import org.onlab.onos.net.device.DeviceService; | ||
21 | +import org.onlab.onos.net.intent.Intent; | ||
22 | +import org.onlab.onos.net.intent.IntentEvent; | ||
23 | +import org.onlab.onos.net.intent.IntentExtensionService; | ||
24 | +import org.onlab.onos.net.intent.IntentListener; | ||
25 | +import org.onlab.onos.net.intent.IntentService; | ||
26 | +import org.onlab.onos.net.intent.OpticalConnectivityIntent; | ||
27 | +import org.onlab.onos.net.intent.PointToPointIntent; | ||
28 | +import org.onlab.onos.net.link.LinkService; | ||
29 | +import org.onlab.onos.net.resource.LinkResourceService; | ||
30 | +import org.onlab.onos.net.topology.LinkWeight; | ||
31 | +import org.onlab.onos.net.topology.Topology; | ||
32 | +import org.onlab.onos.net.topology.TopologyEdge; | ||
33 | + | ||
34 | +import org.onlab.onos.net.topology.TopologyService; | ||
35 | +import org.slf4j.Logger; | ||
36 | +import org.slf4j.LoggerFactory; | ||
37 | + | ||
38 | +/** | ||
39 | + * OpticalPathProvisioner listens event notifications from the Intent F/W. | ||
40 | + * It generates one or more opticalConnectivityIntent(s) and submits (or withdraws) to Intent F/W | ||
41 | + * for adding/releasing capacity at the packet layer. | ||
42 | + * | ||
43 | + */ | ||
44 | + | ||
45 | +@Component(immediate = true) | ||
46 | +public class OpticalPathProvisioner { | ||
47 | + | ||
48 | + protected static final Logger log = LoggerFactory | ||
49 | + .getLogger(OpticalPathProvisioner.class); | ||
50 | + | ||
51 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
52 | + private IntentService intentService; | ||
53 | + | ||
54 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
55 | + private IntentExtensionService intentExtensionService; | ||
56 | + | ||
57 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
58 | + protected LinkService linkService; | ||
59 | + | ||
60 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
61 | + protected DeviceService deviceService; | ||
62 | + | ||
63 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
64 | + protected TopologyService topologyService; | ||
65 | + | ||
66 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
67 | + protected CoreService coreService; | ||
68 | + | ||
69 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
70 | + protected LinkResourceService resourceService; | ||
71 | + | ||
72 | + private ApplicationId appId; | ||
73 | + | ||
74 | + //protected <IntentId> intentIdGenerator; | ||
75 | + | ||
76 | + private final InternalOpticalPathProvisioner pathProvisioner = new InternalOpticalPathProvisioner(); | ||
77 | + | ||
78 | + @Activate | ||
79 | + protected void activate() { | ||
80 | + intentService.addListener(pathProvisioner); | ||
81 | + appId = coreService.registerApplication("org.onlab.onos.optical"); | ||
82 | + log.info("Starting optical path provisoning..."); | ||
83 | + } | ||
84 | + | ||
85 | + @Deactivate | ||
86 | + protected void deactivate() { | ||
87 | + intentService.removeListener(pathProvisioner); | ||
88 | + } | ||
89 | + | ||
90 | + public class InternalOpticalPathProvisioner implements IntentListener { | ||
91 | + @Override | ||
92 | + public void event(IntentEvent event) { | ||
93 | + switch (event.type()) { | ||
94 | + case SUBMITTED: | ||
95 | + break; | ||
96 | + case INSTALLED: | ||
97 | + break; | ||
98 | + case FAILED: | ||
99 | + log.info("intent {} failed, calling optical path provisioning APP.", event.subject()); | ||
100 | + setuplightpath(event.subject()); | ||
101 | + break; | ||
102 | + case WITHDRAWN: | ||
103 | + log.info("intent {} withdrawn.", event.subject()); | ||
104 | + teardownLightpath(event.subject()); | ||
105 | + break; | ||
106 | + default: | ||
107 | + break; | ||
108 | + } | ||
109 | + } | ||
110 | + | ||
111 | + private void setuplightpath(Intent intent) { | ||
112 | + // TODO: considering user policies and optical reach | ||
113 | + if (!intent.equals(PointToPointIntent.class)) { | ||
114 | + return; | ||
115 | + } | ||
116 | + | ||
117 | + PointToPointIntent pktIntent = (PointToPointIntent) intent; | ||
118 | + if (pktIntent.ingressPoint() == null || pktIntent.egressPoint() == null) { | ||
119 | + return; | ||
120 | + } | ||
121 | + | ||
122 | + Topology topology = topologyService.currentTopology(); | ||
123 | + | ||
124 | + LinkWeight weight = new LinkWeight() { | ||
125 | + @Override | ||
126 | + public double weight(TopologyEdge edge) { | ||
127 | + boolean isOptical = false; | ||
128 | + String t = edge.link().annotations().value("linkType"); | ||
129 | + if (t.equals("WDM")) { | ||
130 | + isOptical = true; | ||
131 | + } | ||
132 | + if (isOptical) { | ||
133 | + return 1000; // optical links | ||
134 | + } else { | ||
135 | + return 10; // packet links | ||
136 | + } | ||
137 | + } | ||
138 | + }; | ||
139 | + | ||
140 | + Set<Path> paths = topologyService.getPaths(topology, | ||
141 | + pktIntent.ingressPoint().deviceId(), | ||
142 | + pktIntent.egressPoint().deviceId(), | ||
143 | + weight); | ||
144 | + | ||
145 | + if (paths.isEmpty()) { | ||
146 | + return; | ||
147 | + } | ||
148 | + | ||
149 | + ConnectPoint srcWdmPoint = null; | ||
150 | + ConnectPoint dstWdmPoint = null; | ||
151 | + Iterator<Path> itrPath = paths.iterator(); | ||
152 | + Path firstPath = itrPath.next(); | ||
153 | + log.info(firstPath.toString()); | ||
154 | + | ||
155 | + ArrayList<Map<ConnectPoint, ConnectPoint>> connectionList = new ArrayList<>(); | ||
156 | + | ||
157 | + Iterator<Link> itrLink = firstPath.links().iterator(); | ||
158 | + while (itrLink.hasNext()) { | ||
159 | + Link link1 = itrLink.next(); | ||
160 | + if (!isOpticalLink(link1)) { | ||
161 | + continue; | ||
162 | + } else { | ||
163 | + srcWdmPoint = link1.dst(); | ||
164 | + dstWdmPoint = srcWdmPoint; | ||
165 | + } | ||
166 | + | ||
167 | + while (true) { | ||
168 | + | ||
169 | + if (itrLink.hasNext()) { | ||
170 | + Link link2 = itrLink.next(); | ||
171 | + dstWdmPoint = link2.src(); | ||
172 | + } else { | ||
173 | + break; | ||
174 | + } | ||
175 | + | ||
176 | + if (itrLink.hasNext()) { | ||
177 | + Link link3 = itrLink.next(); | ||
178 | + if (!isOpticalLink(link3)) { | ||
179 | + break; | ||
180 | + } | ||
181 | + } else { | ||
182 | + break; | ||
183 | + } | ||
184 | + } | ||
185 | + | ||
186 | + Map<ConnectPoint, ConnectPoint> pair = | ||
187 | + new HashMap<ConnectPoint, ConnectPoint>(); | ||
188 | + pair.put(srcWdmPoint, dstWdmPoint); | ||
189 | + | ||
190 | + connectionList.add(pair); | ||
191 | + } | ||
192 | + | ||
193 | + for (Map<ConnectPoint, ConnectPoint> map : connectionList) { | ||
194 | + for (Entry<ConnectPoint, ConnectPoint> entry : map.entrySet()) { | ||
195 | + | ||
196 | + ConnectPoint src = entry.getKey(); | ||
197 | + ConnectPoint dst = entry.getValue(); | ||
198 | + | ||
199 | + Intent opticalIntent = new OpticalConnectivityIntent(appId, | ||
200 | + srcWdmPoint, | ||
201 | + dstWdmPoint); | ||
202 | + | ||
203 | + intentService.submit(opticalIntent); | ||
204 | + | ||
205 | + log.info(opticalIntent.toString()); | ||
206 | + } | ||
207 | + } | ||
208 | + | ||
209 | + } | ||
210 | + | ||
211 | + private boolean isOpticalLink(Link link) { | ||
212 | + boolean isOptical = false; | ||
213 | + String t = link.annotations().value("linkType"); | ||
214 | + if (t.equals("WDM") || t.equals("PktOptLink")) { | ||
215 | + isOptical = true; | ||
216 | + } | ||
217 | + return isOptical; | ||
218 | + } | ||
219 | + | ||
220 | + private void teardownLightpath(Intent intent) { | ||
221 | + // TODO: tear down the idle lightpath if the utilization is close to zero. | ||
222 | + } | ||
223 | + | ||
224 | + } | ||
225 | + | ||
226 | +} |
1 | +package org.onlab.onos.optical.testapp; | ||
2 | + | ||
3 | +import static org.slf4j.LoggerFactory.getLogger; | ||
4 | + | ||
5 | +import java.util.HashMap; | ||
6 | +import java.util.Map; | ||
7 | + | ||
8 | +import org.apache.felix.scr.annotations.Activate; | ||
9 | +import org.apache.felix.scr.annotations.Deactivate; | ||
10 | +import org.apache.felix.scr.annotations.Reference; | ||
11 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
12 | +import org.onlab.onos.ApplicationId; | ||
13 | +import org.onlab.onos.CoreService; | ||
14 | +import org.onlab.onos.net.Device; | ||
15 | +import org.onlab.onos.net.DeviceId; | ||
16 | +import org.onlab.onos.net.PortNumber; | ||
17 | +import org.onlab.onos.net.device.DeviceEvent; | ||
18 | +import org.onlab.onos.net.device.DeviceListener; | ||
19 | +import org.onlab.onos.net.device.DeviceService; | ||
20 | +import org.onlab.onos.net.flow.DefaultFlowRule; | ||
21 | +import org.onlab.onos.net.flow.DefaultTrafficSelector; | ||
22 | +import org.onlab.onos.net.flow.DefaultTrafficTreatment; | ||
23 | +import org.onlab.onos.net.flow.FlowRule; | ||
24 | +import org.onlab.onos.net.flow.FlowRuleService; | ||
25 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
26 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
27 | +import org.slf4j.Logger; | ||
28 | + | ||
29 | +/** | ||
30 | + * Sample reactive forwarding application. | ||
31 | + */ | ||
32 | +//@Component(immediate = true) | ||
33 | +public class LambdaForwarding { | ||
34 | + | ||
35 | + private final Logger log = getLogger(getClass()); | ||
36 | + | ||
37 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
38 | + protected FlowRuleService flowRuleService; | ||
39 | + | ||
40 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
41 | + protected CoreService coreService; | ||
42 | + | ||
43 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
44 | + protected DeviceService deviceService; | ||
45 | + | ||
46 | + private ApplicationId appId; | ||
47 | + | ||
48 | + private final InternalDeviceListener listener = new InternalDeviceListener(); | ||
49 | + | ||
50 | + private final Map<DeviceId, Integer> uglyMap = new HashMap<>(); | ||
51 | + | ||
52 | + @Activate | ||
53 | + public void activate() { | ||
54 | + appId = coreService.registerApplication("org.onlab.onos.fwd"); | ||
55 | + | ||
56 | + uglyMap.put(DeviceId.deviceId("of:0000ffffffffff01"), 1); | ||
57 | + uglyMap.put(DeviceId.deviceId("of:0000ffffffffff02"), 2); | ||
58 | + uglyMap.put(DeviceId.deviceId("of:0000ffffffffff03"), 3); | ||
59 | + | ||
60 | + deviceService.addListener(listener); | ||
61 | + | ||
62 | + for (Device d : deviceService.getDevices()) { | ||
63 | + pushRules(d); | ||
64 | + } | ||
65 | + | ||
66 | + | ||
67 | + log.info("Started with Application ID {}", appId.id()); | ||
68 | + } | ||
69 | + | ||
70 | + @Deactivate | ||
71 | + public void deactivate() { | ||
72 | + flowRuleService.removeFlowRulesById(appId); | ||
73 | + | ||
74 | + log.info("Stopped"); | ||
75 | + } | ||
76 | + | ||
77 | + | ||
78 | + private void pushRules(Device device) { | ||
79 | + | ||
80 | + TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); | ||
81 | + TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); | ||
82 | + int inport; | ||
83 | + int outport; | ||
84 | + short lambda = 10; | ||
85 | + byte sigType = 1; | ||
86 | + Integer switchNumber = uglyMap.get(device.id()); | ||
87 | + if (switchNumber == null) { | ||
88 | + return; | ||
89 | + } | ||
90 | + | ||
91 | + switch (switchNumber) { | ||
92 | + case 1: | ||
93 | + inport = 10; | ||
94 | + outport = 20; | ||
95 | + sbuilder.matchInport(PortNumber.portNumber(inport)); | ||
96 | + tbuilder.setOutput(PortNumber.portNumber(outport)).setLambda(lambda); | ||
97 | + break; | ||
98 | + case 2: | ||
99 | + inport = 21; | ||
100 | + outport = 11; | ||
101 | + sbuilder.matchLambda(lambda). | ||
102 | + matchInport(PortNumber.portNumber(inport)); // match sigtype | ||
103 | + tbuilder.setOutput(PortNumber.portNumber(outport)); | ||
104 | + break; | ||
105 | + case 3: | ||
106 | + inport = 30; | ||
107 | + outport = 31; | ||
108 | + sbuilder.matchLambda(lambda). | ||
109 | + matchInport(PortNumber.portNumber(inport)); | ||
110 | + tbuilder.setOutput(PortNumber.portNumber(outport)).setLambda(lambda); | ||
111 | + break; | ||
112 | + default: | ||
113 | + } | ||
114 | + | ||
115 | + TrafficTreatment treatement = tbuilder.build(); | ||
116 | + TrafficSelector selector = sbuilder.build(); | ||
117 | + | ||
118 | + FlowRule f = new DefaultFlowRule(device.id(), selector, | ||
119 | + treatement, 100, appId, 600, false); | ||
120 | + | ||
121 | + flowRuleService.applyFlowRules(f); | ||
122 | + | ||
123 | + | ||
124 | + | ||
125 | + } | ||
126 | + | ||
127 | + public class InternalDeviceListener implements DeviceListener { | ||
128 | + | ||
129 | + @Override | ||
130 | + public void event(DeviceEvent event) { | ||
131 | + switch (event.type()) { | ||
132 | + case DEVICE_ADDED: | ||
133 | + pushRules(event.subject()); | ||
134 | + break; | ||
135 | + case DEVICE_AVAILABILITY_CHANGED: | ||
136 | + break; | ||
137 | + case DEVICE_MASTERSHIP_CHANGED: | ||
138 | + break; | ||
139 | + case DEVICE_REMOVED: | ||
140 | + break; | ||
141 | + case DEVICE_SUSPENDED: | ||
142 | + break; | ||
143 | + case DEVICE_UPDATED: | ||
144 | + break; | ||
145 | + case PORT_ADDED: | ||
146 | + break; | ||
147 | + case PORT_REMOVED: | ||
148 | + break; | ||
149 | + case PORT_UPDATED: | ||
150 | + break; | ||
151 | + default: | ||
152 | + break; | ||
153 | + | ||
154 | + } | ||
155 | + | ||
156 | + } | ||
157 | + | ||
158 | + } | ||
159 | + | ||
160 | + | ||
161 | +} | ||
162 | + | ||
163 | + |
... | @@ -14,6 +14,16 @@ | ... | @@ -14,6 +14,16 @@ |
14 | "attachmentDpid" : "00:00:00:00:00:00:00:a2", | 14 | "attachmentDpid" : "00:00:00:00:00:00:00:a2", |
15 | "attachmentPort" : "1", | 15 | "attachmentPort" : "1", |
16 | "ipAddress" : "192.168.30.1" | 16 | "ipAddress" : "192.168.30.1" |
17 | + }, | ||
18 | + { | ||
19 | + "attachmentDpid" : "00:00:00:00:00:00:00:a6", | ||
20 | + "attachmentPort" : "1", | ||
21 | + "ipAddress" : "192.168.40.1" | ||
22 | + }, | ||
23 | + { | ||
24 | + "attachmentDpid" : "00:00:00:00:00:00:00:a4", | ||
25 | + "attachmentPort" : "4", | ||
26 | + "ipAddress" : "192.168.60.1" | ||
17 | } | 27 | } |
18 | ], | 28 | ], |
19 | "bgpSpeakers" : [ | 29 | "bgpSpeakers" : [ | ... | ... |
1 | +/* | ||
2 | + * Licensed to the Apache Software Foundation (ASF) under one | ||
3 | + * or more contributor license agreements. See the NOTICE file | ||
4 | + * distributed with this work for additional information | ||
5 | + * regarding copyright ownership. The ASF licenses this file | ||
6 | + * to you under the Apache License, Version 2.0 (the | ||
7 | + * "License"); you may not use this file except in compliance | ||
8 | + * with the License. You may obtain a copy of the License at | ||
9 | + * | ||
10 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + * | ||
12 | + * Unless required by applicable law or agreed to in writing, | ||
13 | + * software distributed under the License is distributed on an | ||
14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
15 | + * KIND, either express or implied. See the License for the | ||
16 | + * specific language governing permissions and limitations | ||
17 | + * under the License. | ||
18 | + */ | ||
19 | +package org.onlab.onos.cli.net; | ||
20 | + | ||
21 | +import static org.onlab.onos.net.DeviceId.deviceId; | ||
22 | +import static org.onlab.onos.net.PortNumber.portNumber; | ||
23 | + | ||
24 | +import org.apache.karaf.shell.commands.Argument; | ||
25 | +import org.apache.karaf.shell.commands.Command; | ||
26 | +import org.onlab.onos.net.ConnectPoint; | ||
27 | +import org.onlab.onos.net.DeviceId; | ||
28 | +import org.onlab.onos.net.PortNumber; | ||
29 | +import org.onlab.onos.net.intent.Intent; | ||
30 | +import org.onlab.onos.net.intent.IntentService; | ||
31 | +import org.onlab.onos.net.intent.OpticalConnectivityIntent; | ||
32 | + | ||
33 | +/** | ||
34 | + * Installs optical connectivity intents. | ||
35 | + */ | ||
36 | +@Command(scope = "onos", name = "add-optical-intent", | ||
37 | + description = "Installs optical connectivity intent") | ||
38 | +public class AddOpticalIntentCommand extends ConnectivityIntentCommand { | ||
39 | + | ||
40 | + @Argument(index = 0, name = "ingressDevice", | ||
41 | + description = "Ingress Device/Port Description", | ||
42 | + required = true, multiValued = false) | ||
43 | + String ingressDeviceString = null; | ||
44 | + | ||
45 | + @Argument(index = 1, name = "egressDevice", | ||
46 | + description = "Egress Device/Port Description", | ||
47 | + required = true, multiValued = false) | ||
48 | + String egressDeviceString = null; | ||
49 | + | ||
50 | + @Override | ||
51 | + protected void execute() { | ||
52 | + IntentService service = get(IntentService.class); | ||
53 | + | ||
54 | + DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString)); | ||
55 | + PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString)); | ||
56 | + ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber); | ||
57 | + | ||
58 | + DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString)); | ||
59 | + PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString)); | ||
60 | + ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber); | ||
61 | + | ||
62 | + Intent intent = new OpticalConnectivityIntent(appId(), ingress, egress); | ||
63 | + service.submit(intent); | ||
64 | + } | ||
65 | + | ||
66 | + /** | ||
67 | + * Extracts the port number portion of the ConnectPoint. | ||
68 | + * | ||
69 | + * @param deviceString string representing the device/port | ||
70 | + * @return port number as a string, empty string if the port is not found | ||
71 | + */ | ||
72 | + private String getPortNumber(String deviceString) { | ||
73 | + int slash = deviceString.indexOf('/'); | ||
74 | + if (slash <= 0) { | ||
75 | + return ""; | ||
76 | + } | ||
77 | + return deviceString.substring(slash + 1, deviceString.length()); | ||
78 | + } | ||
79 | + | ||
80 | + /** | ||
81 | + * Extracts the device ID portion of the ConnectPoint. | ||
82 | + * | ||
83 | + * @param deviceString string representing the device/port | ||
84 | + * @return device ID string | ||
85 | + */ | ||
86 | + private String getDeviceId(String deviceString) { | ||
87 | + int slash = deviceString.indexOf('/'); | ||
88 | + if (slash <= 0) { | ||
89 | + return ""; | ||
90 | + } | ||
91 | + return deviceString.substring(0, slash); | ||
92 | + } | ||
93 | +} |
... | @@ -119,6 +119,14 @@ | ... | @@ -119,6 +119,14 @@ |
119 | </optional-completers> | 119 | </optional-completers> |
120 | </command> | 120 | </command> |
121 | <command> | 121 | <command> |
122 | + <action class="org.onlab.onos.cli.net.AddOpticalIntentCommand"/> | ||
123 | + <completers> | ||
124 | + <ref component-id="connectPointCompleter"/> | ||
125 | + <ref component-id="connectPointCompleter"/> | ||
126 | + <null/> | ||
127 | + </completers> | ||
128 | + </command> | ||
129 | + <command> | ||
122 | <action class="org.onlab.onos.cli.net.GetStatistics"/> | 130 | <action class="org.onlab.onos.cli.net.GetStatistics"/> |
123 | <completers> | 131 | <completers> |
124 | <ref component-id="connectPointCompleter"/> | 132 | <ref component-id="connectPointCompleter"/> | ... | ... |
1 | +/* | ||
2 | + * Licensed to the Apache Software Foundation (ASF) under one | ||
3 | + * or more contributor license agreements. See the NOTICE file | ||
4 | + * distributed with this work for additional information | ||
5 | + * regarding copyright ownership. The ASF licenses this file | ||
6 | + * to you under the Apache License, Version 2.0 (the | ||
7 | + * "License"); you may not use this file except in compliance | ||
8 | + * with the License. You may obtain a copy of the License at | ||
9 | + * | ||
10 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + * | ||
12 | + * Unless required by applicable law or agreed to in writing, | ||
13 | + * software distributed under the License is distributed on an | ||
14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
15 | + * KIND, either express or implied. See the License for the | ||
16 | + * specific language governing permissions and limitations | ||
17 | + * under the License. | ||
18 | + */ | ||
19 | +package org.onlab.onos.codec; | ||
20 | + | ||
21 | +import java.util.Set; | ||
22 | + | ||
23 | +/** | ||
24 | + * Service for registering and retrieving JSON codecs for various entities. | ||
25 | + */ | ||
26 | +public interface CodecService { | ||
27 | + | ||
28 | + /** | ||
29 | + * Returns the set of classes with currently registered codecs. | ||
30 | + * | ||
31 | + * @return set of entity classes | ||
32 | + */ | ||
33 | + Set<Class<?>> getCodecs(); | ||
34 | + | ||
35 | + /** | ||
36 | + * Returns the JSON codec for the specified entity class. | ||
37 | + * | ||
38 | + * @param entityClass entity class | ||
39 | + * @return JSON codec; null if no codec available for the class | ||
40 | + */ | ||
41 | + JsonCodec getCodec(Class<?> entityClass); | ||
42 | + | ||
43 | + /** | ||
44 | + * Registers the specified JSON codec for the given entity class. | ||
45 | + * | ||
46 | + * @param entityClass entity class | ||
47 | + * @param codec JSON codec | ||
48 | + */ | ||
49 | + void registerCodec(Class<?> entityClass, JsonCodec codec); | ||
50 | + | ||
51 | + /** | ||
52 | + * Unregisters the JSON codec for the specified entity class. | ||
53 | + * | ||
54 | + * @param entityClass entity class | ||
55 | + */ | ||
56 | + void unregisterCodec(Class<?> entityClass); | ||
57 | + | ||
58 | +} |
1 | +/* | ||
2 | + * Licensed to the Apache Software Foundation (ASF) under one | ||
3 | + * or more contributor license agreements. See the NOTICE file | ||
4 | + * distributed with this work for additional information | ||
5 | + * regarding copyright ownership. The ASF licenses this file | ||
6 | + * to you under the Apache License, Version 2.0 (the | ||
7 | + * "License"); you may not use this file except in compliance | ||
8 | + * with the License. You may obtain a copy of the License at | ||
9 | + * | ||
10 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + * | ||
12 | + * Unless required by applicable law or agreed to in writing, | ||
13 | + * software distributed under the License is distributed on an | ||
14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
15 | + * KIND, either express or implied. See the License for the | ||
16 | + * specific language governing permissions and limitations | ||
17 | + * under the License. | ||
18 | + */ | ||
19 | +package org.onlab.onos.codec; | ||
20 | + | ||
21 | +import com.fasterxml.jackson.databind.JsonNode; | ||
22 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
23 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
24 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
25 | + | ||
26 | +import java.util.ArrayList; | ||
27 | +import java.util.List; | ||
28 | + | ||
29 | +/** | ||
30 | + * Abstraction of a codec capable for encoding/decoding arbitrary objects to/from JSON. | ||
31 | + */ | ||
32 | +public abstract class JsonCodec<T> { | ||
33 | + | ||
34 | + /** | ||
35 | + * Encodes the specified entity into JSON. | ||
36 | + * | ||
37 | + * @param entity entity to encode | ||
38 | + * @param mapper object mapper | ||
39 | + * @return JSON node | ||
40 | + * @throws java.lang.UnsupportedOperationException if the codec does not | ||
41 | + * support encode operations | ||
42 | + */ | ||
43 | + public abstract ObjectNode encode(T entity, ObjectMapper mapper); | ||
44 | + | ||
45 | + /** | ||
46 | + * Decodes the specified entity from JSON. | ||
47 | + * | ||
48 | + * @param json JSON to decode | ||
49 | + * @return decoded entity | ||
50 | + * @throws java.lang.UnsupportedOperationException if the codec does not | ||
51 | + * support decode operations | ||
52 | + */ | ||
53 | + public abstract T decode(ObjectNode json); | ||
54 | + | ||
55 | + /** | ||
56 | + * Encodes the collection of the specified entities. | ||
57 | + * | ||
58 | + * @param entities collection of entities to encode | ||
59 | + * @param mapper object mapper | ||
60 | + * @return JSON array | ||
61 | + * @throws java.lang.UnsupportedOperationException if the codec does not | ||
62 | + * support encode operations | ||
63 | + */ | ||
64 | + public ArrayNode encode(Iterable<T> entities, ObjectMapper mapper) { | ||
65 | + ArrayNode result = mapper.createArrayNode(); | ||
66 | + for (T entity : entities) { | ||
67 | + result.add(encode(entity, mapper)); | ||
68 | + } | ||
69 | + return result; | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * Decodes the specified JSON array into a collection of entities. | ||
74 | + * | ||
75 | + * @param json JSON array to decode | ||
76 | + * @return collection of decoded entities | ||
77 | + * @throws java.lang.UnsupportedOperationException if the codec does not | ||
78 | + * support decode operations | ||
79 | + */ | ||
80 | + public List<T> decode(ArrayNode json) { | ||
81 | + List<T> result = new ArrayList<>(); | ||
82 | + for (JsonNode node : json) { | ||
83 | + result.add(decode((ObjectNode) node)); | ||
84 | + } | ||
85 | + return result; | ||
86 | + } | ||
87 | + | ||
88 | +} |
1 | +/* | ||
2 | + * Licensed to the Apache Software Foundation (ASF) under one | ||
3 | + * or more contributor license agreements. See the NOTICE file | ||
4 | + * distributed with this work for additional information | ||
5 | + * regarding copyright ownership. The ASF licenses this file | ||
6 | + * to you under the Apache License, Version 2.0 (the | ||
7 | + * "License"); you may not use this file except in compliance | ||
8 | + * with the License. You may obtain a copy of the License at | ||
9 | + * | ||
10 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + * | ||
12 | + * Unless required by applicable law or agreed to in writing, | ||
13 | + * software distributed under the License is distributed on an | ||
14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
15 | + * KIND, either express or implied. See the License for the | ||
16 | + * specific language governing permissions and limitations | ||
17 | + * under the License. | ||
18 | + */ | ||
19 | + | ||
20 | +/** | ||
21 | + * Base JSON codec abstraction and a service for tracking various JSON codecs. | ||
22 | + */ | ||
23 | +package org.onlab.onos.codec; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -18,7 +18,7 @@ | ... | @@ -18,7 +18,7 @@ |
18 | */ | 18 | */ |
19 | package org.onlab.onos.net.flow; | 19 | package org.onlab.onos.net.flow; |
20 | 20 | ||
21 | -import java.util.List; | 21 | +import java.util.Set; |
22 | 22 | ||
23 | /** | 23 | /** |
24 | * Interface capturing the result of a batch operation. | 24 | * Interface capturing the result of a batch operation. |
... | @@ -33,9 +33,9 @@ public interface BatchOperationResult<T> { | ... | @@ -33,9 +33,9 @@ public interface BatchOperationResult<T> { |
33 | boolean isSuccess(); | 33 | boolean isSuccess(); |
34 | 34 | ||
35 | /** | 35 | /** |
36 | - * Obtains a list of items which failed. | 36 | + * Obtains a set of items which failed. |
37 | - * @return a list of failures | 37 | + * @return a set of failures |
38 | */ | 38 | */ |
39 | - List<T> failedItems(); | 39 | + Set<T> failedItems(); |
40 | 40 | ||
41 | } | 41 | } | ... | ... |
... | @@ -18,19 +18,19 @@ | ... | @@ -18,19 +18,19 @@ |
18 | */ | 18 | */ |
19 | package org.onlab.onos.net.flow; | 19 | package org.onlab.onos.net.flow; |
20 | 20 | ||
21 | -import java.util.List; | 21 | +import java.util.Set; |
22 | 22 | ||
23 | -import com.google.common.collect.ImmutableList; | 23 | +import com.google.common.collect.ImmutableSet; |
24 | 24 | ||
25 | public class CompletedBatchOperation implements BatchOperationResult<FlowEntry> { | 25 | public class CompletedBatchOperation implements BatchOperationResult<FlowEntry> { |
26 | 26 | ||
27 | 27 | ||
28 | private final boolean success; | 28 | private final boolean success; |
29 | - private final List<FlowEntry> failures; | 29 | + private final Set<FlowEntry> failures; |
30 | 30 | ||
31 | - public CompletedBatchOperation(boolean success, List<FlowEntry> failures) { | 31 | + public CompletedBatchOperation(boolean success, Set<FlowEntry> failures) { |
32 | this.success = success; | 32 | this.success = success; |
33 | - this.failures = ImmutableList.copyOf(failures); | 33 | + this.failures = ImmutableSet.copyOf(failures); |
34 | } | 34 | } |
35 | 35 | ||
36 | @Override | 36 | @Override |
... | @@ -39,7 +39,7 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowEntry> | ... | @@ -39,7 +39,7 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowEntry> |
39 | } | 39 | } |
40 | 40 | ||
41 | @Override | 41 | @Override |
42 | - public List<FlowEntry> failedItems() { | 42 | + public Set<FlowEntry> failedItems() { |
43 | return failures; | 43 | return failures; |
44 | } | 44 | } |
45 | 45 | ... | ... |
... | @@ -55,6 +55,16 @@ public final class DefaultTrafficSelector implements TrafficSelector { | ... | @@ -55,6 +55,16 @@ public final class DefaultTrafficSelector implements TrafficSelector { |
55 | } | 55 | } |
56 | 56 | ||
57 | @Override | 57 | @Override |
58 | + public Criterion getCriterion(Criterion.Type type) { | ||
59 | + for (Criterion c : criteria) { | ||
60 | + if (c.type() == type) { | ||
61 | + return c; | ||
62 | + } | ||
63 | + } | ||
64 | + return null; | ||
65 | + } | ||
66 | + | ||
67 | + @Override | ||
58 | public int hashCode() { | 68 | public int hashCode() { |
59 | return Objects.hash(criteria); | 69 | return Objects.hash(criteria); |
60 | } | 70 | } |
... | @@ -176,6 +186,17 @@ public final class DefaultTrafficSelector implements TrafficSelector { | ... | @@ -176,6 +186,17 @@ public final class DefaultTrafficSelector implements TrafficSelector { |
176 | } | 186 | } |
177 | 187 | ||
178 | @Override | 188 | @Override |
189 | + public Builder matchLambda(Short lambda) { | ||
190 | + return add(Criteria.matchLambda(lambda)); | ||
191 | + } | ||
192 | + | ||
193 | + @Override | ||
194 | + public Builder matchOpticalSignalType(Byte signalType) { | ||
195 | + return add(Criteria.matchOpticalSignalType(signalType)); | ||
196 | + | ||
197 | + } | ||
198 | + | ||
199 | + @Override | ||
179 | public TrafficSelector build() { | 200 | public TrafficSelector build() { |
180 | return new DefaultTrafficSelector(ImmutableSet.copyOf(selector.values())); | 201 | return new DefaultTrafficSelector(ImmutableSet.copyOf(selector.values())); |
181 | } | 202 | } | ... | ... |
... | @@ -137,6 +137,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { | ... | @@ -137,6 +137,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { |
137 | case OUTPUT: | 137 | case OUTPUT: |
138 | outputs.add(instruction); | 138 | outputs.add(instruction); |
139 | break; | 139 | break; |
140 | + case L0MODIFICATION: | ||
140 | case L2MODIFICATION: | 141 | case L2MODIFICATION: |
141 | case L3MODIFICATION: | 142 | case L3MODIFICATION: |
142 | // TODO: enforce modification order if any | 143 | // TODO: enforce modification order if any |
... | @@ -193,6 +194,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { | ... | @@ -193,6 +194,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { |
193 | } | 194 | } |
194 | 195 | ||
195 | @Override | 196 | @Override |
197 | + public Builder setLambda(short lambda) { | ||
198 | + return add(Instructions.modL0Lambda(lambda)); | ||
199 | + } | ||
200 | + | ||
201 | + @Override | ||
196 | public TrafficTreatment build() { | 202 | public TrafficTreatment build() { |
197 | 203 | ||
198 | //If we are dropping should we just return an emptry list? | 204 | //If we are dropping should we just return an emptry list? | ... | ... |
1 | +package org.onlab.onos.net.flow; | ||
2 | + | ||
3 | +import org.onlab.onos.event.AbstractEvent; | ||
4 | + | ||
5 | +/** | ||
6 | + * Describes flow rule batch event. | ||
7 | + */ | ||
8 | +public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.Type, FlowRuleBatchRequest> { | ||
9 | + | ||
10 | + /** | ||
11 | + * Type of flow rule events. | ||
12 | + */ | ||
13 | + public enum Type { | ||
14 | + | ||
15 | + /** | ||
16 | + * Signifies that a batch operation has been initiated. | ||
17 | + */ | ||
18 | + BATCH_OPERATION_REQUESTED, | ||
19 | + | ||
20 | + /** | ||
21 | + * Signifies that a batch operation has completed. | ||
22 | + */ | ||
23 | + BATCH_OPERATION_COMPLETED, | ||
24 | + } | ||
25 | + | ||
26 | + private final CompletedBatchOperation result; | ||
27 | + | ||
28 | + /** | ||
29 | + * Constructs a new FlowRuleBatchEvent. | ||
30 | + * @param request batch operation request. | ||
31 | + * @return event. | ||
32 | + */ | ||
33 | + public static FlowRuleBatchEvent requested(FlowRuleBatchRequest request) { | ||
34 | + FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_REQUESTED, request, null); | ||
35 | + return event; | ||
36 | + } | ||
37 | + | ||
38 | + /** | ||
39 | + * Constructs a new FlowRuleBatchEvent. | ||
40 | + * @param request batch operation request. | ||
41 | + * @param result completed batch operation result. | ||
42 | + * @return event. | ||
43 | + */ | ||
44 | + public static FlowRuleBatchEvent completed(FlowRuleBatchRequest request, CompletedBatchOperation result) { | ||
45 | + FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_COMPLETED, request, result); | ||
46 | + return event; | ||
47 | + } | ||
48 | + | ||
49 | + /** | ||
50 | + * Returns the result of this batch operation. | ||
51 | + * @return batch operation result. | ||
52 | + */ | ||
53 | + public CompletedBatchOperation result() { | ||
54 | + return result; | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * Creates an event of a given type and for the specified flow rule batch. | ||
59 | + * | ||
60 | + * @param type flow rule batch event type | ||
61 | + * @param batch event flow rule batch subject | ||
62 | + */ | ||
63 | + private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, CompletedBatchOperation result) { | ||
64 | + super(type, request); | ||
65 | + this.result = result; | ||
66 | + } | ||
67 | +} |
1 | +package org.onlab.onos.net.flow; | ||
2 | + | ||
3 | +import java.util.Collections; | ||
4 | +import java.util.List; | ||
5 | + | ||
6 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | ||
7 | + | ||
8 | +import com.google.common.collect.Lists; | ||
9 | + | ||
10 | +public class FlowRuleBatchRequest { | ||
11 | + | ||
12 | + private final int batchId; | ||
13 | + private final List<FlowEntry> toAdd; | ||
14 | + private final List<FlowEntry> toRemove; | ||
15 | + | ||
16 | + public FlowRuleBatchRequest(int batchId, List<FlowEntry> toAdd, List<FlowEntry> toRemove) { | ||
17 | + this.batchId = batchId; | ||
18 | + this.toAdd = Collections.unmodifiableList(toAdd); | ||
19 | + this.toRemove = Collections.unmodifiableList(toRemove); | ||
20 | + } | ||
21 | + | ||
22 | + public List<FlowEntry> toAdd() { | ||
23 | + return toAdd; | ||
24 | + } | ||
25 | + | ||
26 | + public List<FlowEntry> toRemove() { | ||
27 | + return toRemove; | ||
28 | + } | ||
29 | + | ||
30 | + public FlowRuleBatchOperation asBatchOperation() { | ||
31 | + List<FlowRuleBatchEntry> entries = Lists.newArrayList(); | ||
32 | + for (FlowEntry e : toAdd) { | ||
33 | + entries.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, e)); | ||
34 | + } | ||
35 | + for (FlowEntry e : toRemove) { | ||
36 | + entries.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, e)); | ||
37 | + } | ||
38 | + return new FlowRuleBatchOperation(entries); | ||
39 | + } | ||
40 | + | ||
41 | + public int batchId() { | ||
42 | + return batchId; | ||
43 | + } | ||
44 | +} |
... | @@ -18,11 +18,11 @@ | ... | @@ -18,11 +18,11 @@ |
18 | */ | 18 | */ |
19 | package org.onlab.onos.net.flow; | 19 | package org.onlab.onos.net.flow; |
20 | 20 | ||
21 | -import java.util.concurrent.Future; | ||
22 | - | ||
23 | import org.onlab.onos.ApplicationId; | 21 | import org.onlab.onos.ApplicationId; |
24 | import org.onlab.onos.net.provider.Provider; | 22 | import org.onlab.onos.net.provider.Provider; |
25 | 23 | ||
24 | +import com.google.common.util.concurrent.ListenableFuture; | ||
25 | + | ||
26 | /** | 26 | /** |
27 | * Abstraction of a flow rule provider. | 27 | * Abstraction of a flow rule provider. |
28 | */ | 28 | */ |
... | @@ -60,6 +60,6 @@ public interface FlowRuleProvider extends Provider { | ... | @@ -60,6 +60,6 @@ public interface FlowRuleProvider extends Provider { |
60 | * @param batch a batch of flow rules | 60 | * @param batch a batch of flow rules |
61 | * @return a future indicating the status of this execution | 61 | * @return a future indicating the status of this execution |
62 | */ | 62 | */ |
63 | - Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch); | 63 | + ListenableFuture<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch); |
64 | 64 | ||
65 | } | 65 | } | ... | ... |
... | @@ -18,6 +18,8 @@ | ... | @@ -18,6 +18,8 @@ |
18 | */ | 18 | */ |
19 | package org.onlab.onos.net.flow; | 19 | package org.onlab.onos.net.flow; |
20 | 20 | ||
21 | +import java.util.concurrent.Future; | ||
22 | + | ||
21 | import org.onlab.onos.ApplicationId; | 23 | import org.onlab.onos.ApplicationId; |
22 | import org.onlab.onos.net.DeviceId; | 24 | import org.onlab.onos.net.DeviceId; |
23 | import org.onlab.onos.store.Store; | 25 | import org.onlab.onos.store.Store; |
... | @@ -25,7 +27,7 @@ import org.onlab.onos.store.Store; | ... | @@ -25,7 +27,7 @@ import org.onlab.onos.store.Store; |
25 | /** | 27 | /** |
26 | * Manages inventory of flow rules; not intended for direct use. | 28 | * Manages inventory of flow rules; not intended for direct use. |
27 | */ | 29 | */ |
28 | -public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegate> { | 30 | +public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDelegate> { |
29 | 31 | ||
30 | /** | 32 | /** |
31 | * Returns the number of flow rule in the store. | 33 | * Returns the number of flow rule in the store. |
... | @@ -59,12 +61,26 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat | ... | @@ -59,12 +61,26 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat |
59 | Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId); | 61 | Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId); |
60 | 62 | ||
61 | /** | 63 | /** |
64 | + // TODO: Better description of method behavior. | ||
62 | * Stores a new flow rule without generating events. | 65 | * Stores a new flow rule without generating events. |
63 | * | 66 | * |
64 | * @param rule the flow rule to add | 67 | * @param rule the flow rule to add |
65 | - * @return true if the rule should be handled locally | ||
66 | */ | 68 | */ |
67 | - boolean storeFlowRule(FlowRule rule); | 69 | + void storeFlowRule(FlowRule rule); |
70 | + | ||
71 | + /** | ||
72 | + * Stores a batch of flow rules. | ||
73 | + * @param batchOperation batch of flow rules. | ||
74 | + * @return Future response indicating success/failure of the batch operation | ||
75 | + * all the way down to the device. | ||
76 | + */ | ||
77 | + Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation batchOperation); | ||
78 | + | ||
79 | + /** | ||
80 | + * Invoked on the completion of a storeBatch operation. | ||
81 | + * @param result | ||
82 | + */ | ||
83 | + void batchOperationComplete(FlowRuleBatchEvent event); | ||
68 | 84 | ||
69 | /** | 85 | /** |
70 | * Marks a flow rule for deletion. Actual deletion will occur | 86 | * Marks a flow rule for deletion. Actual deletion will occur |
... | @@ -73,7 +89,7 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat | ... | @@ -73,7 +89,7 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat |
73 | * @param rule the flow rule to delete | 89 | * @param rule the flow rule to delete |
74 | * @return true if the rule should be handled locally | 90 | * @return true if the rule should be handled locally |
75 | */ | 91 | */ |
76 | - boolean deleteFlowRule(FlowRule rule); | 92 | + void deleteFlowRule(FlowRule rule); |
77 | 93 | ||
78 | /** | 94 | /** |
79 | * Stores a new flow rule, or updates an existing entry. | 95 | * Stores a new flow rule, or updates an existing entry. | ... | ... |
... | @@ -23,5 +23,5 @@ import org.onlab.onos.store.StoreDelegate; | ... | @@ -23,5 +23,5 @@ import org.onlab.onos.store.StoreDelegate; |
23 | /** | 23 | /** |
24 | * Flow rule store delegate abstraction. | 24 | * Flow rule store delegate abstraction. |
25 | */ | 25 | */ |
26 | -public interface FlowRuleStoreDelegate extends StoreDelegate<FlowRuleEvent> { | 26 | +public interface FlowRuleStoreDelegate extends StoreDelegate<FlowRuleBatchEvent> { |
27 | } | 27 | } | ... | ... |
... | @@ -39,6 +39,15 @@ public interface TrafficSelector { | ... | @@ -39,6 +39,15 @@ public interface TrafficSelector { |
39 | Set<Criterion> criteria(); | 39 | Set<Criterion> criteria(); |
40 | 40 | ||
41 | /** | 41 | /** |
42 | + * Returns the selection criterion for a particular type, if it exists in | ||
43 | + * this traffic selector. | ||
44 | + * | ||
45 | + * @param type criterion type to look up | ||
46 | + * @return the criterion of the specified type if one exists, otherwise null | ||
47 | + */ | ||
48 | + Criterion getCriterion(Criterion.Type type); | ||
49 | + | ||
50 | + /** | ||
42 | * Builder of traffic selector entities. | 51 | * Builder of traffic selector entities. |
43 | */ | 52 | */ |
44 | public interface Builder { | 53 | public interface Builder { |
... | @@ -130,6 +139,20 @@ public interface TrafficSelector { | ... | @@ -130,6 +139,20 @@ public interface TrafficSelector { |
130 | public Builder matchTcpDst(Short tcpPort); | 139 | public Builder matchTcpDst(Short tcpPort); |
131 | 140 | ||
132 | /** | 141 | /** |
142 | + * Matches an optical signal ID or lambda. | ||
143 | + * @param lambda | ||
144 | + * @return a selection builder | ||
145 | + */ | ||
146 | + public Builder matchLambda(Short lambda); | ||
147 | + | ||
148 | + /** | ||
149 | + * Matches an optical Signal Type. | ||
150 | + * @param signalType | ||
151 | + * @return a selection builder | ||
152 | + */ | ||
153 | + public Builder matchOpticalSignalType(Byte signalType); | ||
154 | + | ||
155 | + /** | ||
133 | * Builds an immutable traffic selector. | 156 | * Builds an immutable traffic selector. |
134 | * | 157 | * |
135 | * @return traffic selector | 158 | * @return traffic selector | ... | ... |
... | @@ -105,6 +105,13 @@ public interface TrafficTreatment { | ... | @@ -105,6 +105,13 @@ public interface TrafficTreatment { |
105 | public Builder setIpDst(IpPrefix addr); | 105 | public Builder setIpDst(IpPrefix addr); |
106 | 106 | ||
107 | /** | 107 | /** |
108 | + * Sets the optical channel ID or lambda. | ||
109 | + * @param lambda optical channel ID | ||
110 | + * @return a treatment builder | ||
111 | + */ | ||
112 | + public Builder setLambda(short lambda); | ||
113 | + | ||
114 | + /** | ||
108 | * Builds an immutable traffic treatment descriptor. | 115 | * Builds an immutable traffic treatment descriptor. |
109 | * | 116 | * |
110 | * @return traffic treatment | 117 | * @return traffic treatment | ... | ... |
... | @@ -151,10 +151,30 @@ public final class Criteria { | ... | @@ -151,10 +151,30 @@ public final class Criteria { |
151 | return new TcpPortCriterion(tcpPort, Type.TCP_DST); | 151 | return new TcpPortCriterion(tcpPort, Type.TCP_DST); |
152 | } | 152 | } |
153 | 153 | ||
154 | - /* | 154 | + /** |
155 | - * Implementations of criteria. | 155 | + * Creates a match on lambda field using the specified value. |
156 | + * | ||
157 | + * @param lambda | ||
158 | + * @return match criterion | ||
156 | */ | 159 | */ |
160 | + public static Criterion matchLambda(Short lambda) { | ||
161 | + return new LambdaCriterion(lambda, Type.OCH_SIGID); | ||
162 | + } | ||
163 | + | ||
164 | + /** | ||
165 | + * Creates a match on lambda field using the specified value. | ||
166 | + * | ||
167 | + * @param lambda | ||
168 | + * @return match criterion | ||
169 | + */ | ||
170 | + public static Criterion matchOpticalSignalType(Byte lambda) { | ||
171 | + return new OpticalSignalTypeCriterion(lambda, Type.OCH_SIGTYPE); | ||
172 | + } | ||
157 | 173 | ||
174 | + | ||
175 | + /** | ||
176 | + * Implementations of criteria. | ||
177 | + */ | ||
158 | public static final class PortCriterion implements Criterion { | 178 | public static final class PortCriterion implements Criterion { |
159 | private final PortNumber port; | 179 | private final PortNumber port; |
160 | 180 | ||
... | @@ -523,4 +543,93 @@ public final class Criteria { | ... | @@ -523,4 +543,93 @@ public final class Criteria { |
523 | return false; | 543 | return false; |
524 | } | 544 | } |
525 | } | 545 | } |
546 | + | ||
547 | + public static final class LambdaCriterion implements Criterion { | ||
548 | + | ||
549 | + private final short lambda; | ||
550 | + private final Type type; | ||
551 | + | ||
552 | + public LambdaCriterion(short lambda, Type type) { | ||
553 | + this.lambda = lambda; | ||
554 | + this.type = type; | ||
555 | + } | ||
556 | + | ||
557 | + @Override | ||
558 | + public Type type() { | ||
559 | + return this.type; | ||
560 | + } | ||
561 | + | ||
562 | + public Short lambda() { | ||
563 | + return this.lambda; | ||
564 | + } | ||
565 | + | ||
566 | + @Override | ||
567 | + public String toString() { | ||
568 | + return toStringHelper(type().toString()) | ||
569 | + .add("lambda", lambda).toString(); | ||
570 | + } | ||
571 | + | ||
572 | + @Override | ||
573 | + public int hashCode() { | ||
574 | + return Objects.hash(lambda, type); | ||
575 | + } | ||
576 | + | ||
577 | + @Override | ||
578 | + public boolean equals(Object obj) { | ||
579 | + if (this == obj) { | ||
580 | + return true; | ||
581 | + } | ||
582 | + if (obj instanceof LambdaCriterion) { | ||
583 | + LambdaCriterion that = (LambdaCriterion) obj; | ||
584 | + return Objects.equals(lambda, that.lambda) && | ||
585 | + Objects.equals(type, that.type); | ||
586 | + } | ||
587 | + return false; | ||
588 | + } | ||
589 | + } | ||
590 | + | ||
591 | + public static final class OpticalSignalTypeCriterion implements Criterion { | ||
592 | + | ||
593 | + private final byte signalType; | ||
594 | + private final Type type; | ||
595 | + | ||
596 | + public OpticalSignalTypeCriterion(byte signalType, Type type) { | ||
597 | + this.signalType = signalType; | ||
598 | + this.type = type; | ||
599 | + } | ||
600 | + | ||
601 | + @Override | ||
602 | + public Type type() { | ||
603 | + return this.type; | ||
604 | + } | ||
605 | + | ||
606 | + public Byte signalType() { | ||
607 | + return this.signalType; | ||
608 | + } | ||
609 | + | ||
610 | + @Override | ||
611 | + public String toString() { | ||
612 | + return toStringHelper(type().toString()) | ||
613 | + .add("signalType", signalType).toString(); | ||
614 | + } | ||
615 | + | ||
616 | + @Override | ||
617 | + public int hashCode() { | ||
618 | + return Objects.hash(signalType, type); | ||
619 | + } | ||
620 | + | ||
621 | + @Override | ||
622 | + public boolean equals(Object obj) { | ||
623 | + if (this == obj) { | ||
624 | + return true; | ||
625 | + } | ||
626 | + if (obj instanceof OpticalSignalTypeCriterion) { | ||
627 | + OpticalSignalTypeCriterion that = (OpticalSignalTypeCriterion) obj; | ||
628 | + return Objects.equals(signalType, that.signalType) && | ||
629 | + Objects.equals(type, that.type); | ||
630 | + } | ||
631 | + return false; | ||
632 | + } | ||
633 | + } | ||
634 | + | ||
526 | } | 635 | } | ... | ... |
... | @@ -108,7 +108,11 @@ public interface Criterion { | ... | @@ -108,7 +108,11 @@ public interface Criterion { |
108 | /** Logical Port Metadata. */ | 108 | /** Logical Port Metadata. */ |
109 | TUNNEL_ID, | 109 | TUNNEL_ID, |
110 | /** IPv6 Extension Header pseudo-field. */ | 110 | /** IPv6 Extension Header pseudo-field. */ |
111 | - IPV6_EXTHDR | 111 | + IPV6_EXTHDR, |
112 | + /** Optical channel signal ID (lambda). */ | ||
113 | + OCH_SIGID, | ||
114 | + /** Optical channel signal type (fixed or flexible). */ | ||
115 | + OCH_SIGTYPE | ||
112 | } | 116 | } |
113 | 117 | ||
114 | /** | 118 | /** | ... | ... |
... | @@ -43,6 +43,11 @@ public interface Instruction { | ... | @@ -43,6 +43,11 @@ public interface Instruction { |
43 | GROUP, | 43 | GROUP, |
44 | 44 | ||
45 | /** | 45 | /** |
46 | + * Signifies that the traffic should be modified in L0 way. | ||
47 | + */ | ||
48 | + L0MODIFICATION, | ||
49 | + | ||
50 | + /** | ||
46 | * Signifies that the traffic should be modified in L2 way. | 51 | * Signifies that the traffic should be modified in L2 way. |
47 | */ | 52 | */ |
48 | L2MODIFICATION, | 53 | L2MODIFICATION, | ... | ... |
... | @@ -24,6 +24,8 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -24,6 +24,8 @@ import static com.google.common.base.Preconditions.checkNotNull; |
24 | import java.util.Objects; | 24 | import java.util.Objects; |
25 | 25 | ||
26 | import org.onlab.onos.net.PortNumber; | 26 | import org.onlab.onos.net.PortNumber; |
27 | +import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.L0SubType; | ||
28 | +import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction; | ||
27 | import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.L2SubType; | 29 | import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.L2SubType; |
28 | import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; | 30 | import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; |
29 | import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.L3SubType; | 31 | import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.L3SubType; |
... | @@ -62,6 +64,16 @@ public final class Instructions { | ... | @@ -62,6 +64,16 @@ public final class Instructions { |
62 | } | 64 | } |
63 | 65 | ||
64 | /** | 66 | /** |
67 | + * Creates a l0 modification. | ||
68 | + * @param lambda the lambda to modify to. | ||
69 | + * @return a l0 modification | ||
70 | + */ | ||
71 | + public static L0ModificationInstruction modL0Lambda(short lambda) { | ||
72 | + checkNotNull(lambda, "L0 lambda cannot be null"); | ||
73 | + return new ModLambdaInstruction(L0SubType.LAMBDA, lambda); | ||
74 | + } | ||
75 | + | ||
76 | + /** | ||
65 | * Creates a l2 src modification. | 77 | * Creates a l2 src modification. |
66 | * @param addr the mac address to modify to. | 78 | * @param addr the mac address to modify to. |
67 | * @return a l2 modification | 79 | * @return a l2 modification | ... | ... |
core/api/src/main/java/org/onlab/onos/net/flow/instructions/L0ModificationInstruction.java
0 → 100644
1 | +package org.onlab.onos.net.flow.instructions; | ||
2 | + | ||
3 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
4 | + | ||
5 | +import java.util.Objects; | ||
6 | + | ||
7 | +public abstract class L0ModificationInstruction implements Instruction { | ||
8 | + | ||
9 | + /** | ||
10 | + * Represents the type of traffic treatment. | ||
11 | + */ | ||
12 | + public enum L0SubType { | ||
13 | + /** | ||
14 | + * Lambda modification. | ||
15 | + */ | ||
16 | + LAMBDA | ||
17 | + | ||
18 | + //TODO: remaining types | ||
19 | + } | ||
20 | + | ||
21 | + public abstract L0SubType subtype(); | ||
22 | + | ||
23 | + @Override | ||
24 | + public Type type() { | ||
25 | + return Type.L0MODIFICATION; | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * Represents a L0 lambda modification instruction. | ||
30 | + */ | ||
31 | + public static final class ModLambdaInstruction extends L0ModificationInstruction { | ||
32 | + | ||
33 | + private final L0SubType subtype; | ||
34 | + private final short lambda; | ||
35 | + | ||
36 | + public ModLambdaInstruction(L0SubType subType, short lambda) { | ||
37 | + this.subtype = subType; | ||
38 | + this.lambda = lambda; | ||
39 | + } | ||
40 | + | ||
41 | + @Override | ||
42 | + public L0SubType subtype() { | ||
43 | + return this.subtype; | ||
44 | + } | ||
45 | + | ||
46 | + public short lambda() { | ||
47 | + return this.lambda; | ||
48 | + } | ||
49 | + | ||
50 | + @Override | ||
51 | + public String toString() { | ||
52 | + return toStringHelper(subtype().toString()) | ||
53 | + .add("lambda", lambda).toString(); | ||
54 | + } | ||
55 | + | ||
56 | + @Override | ||
57 | + public int hashCode() { | ||
58 | + return Objects.hash(lambda, type(), subtype); | ||
59 | + } | ||
60 | + | ||
61 | + @Override | ||
62 | + public boolean equals(Object obj) { | ||
63 | + if (this == obj) { | ||
64 | + return true; | ||
65 | + } | ||
66 | + if (obj instanceof ModLambdaInstruction) { | ||
67 | + ModLambdaInstruction that = (ModLambdaInstruction) obj; | ||
68 | + return Objects.equals(lambda, that.lambda) && | ||
69 | + Objects.equals(this.type(), that.type()) && | ||
70 | + Objects.equals(subtype, that.subtype); | ||
71 | + } | ||
72 | + return false; | ||
73 | + } | ||
74 | + } | ||
75 | +} |
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import org.onlab.onos.ApplicationId; | ||
4 | +import org.onlab.onos.net.ConnectPoint; | ||
5 | + | ||
6 | +/** | ||
7 | + * An optical layer Intent for a connectivity from one Transponder port to another | ||
8 | + * Transponder port. No trafficSelector as well as trafficTreament are needed. | ||
9 | + * | ||
10 | + */ | ||
11 | +public class OpticalConnectivityIntent extends Intent { | ||
12 | + protected ConnectPoint src; | ||
13 | + protected ConnectPoint dst; | ||
14 | + | ||
15 | + /** | ||
16 | + * Constructor. | ||
17 | + * | ||
18 | + * @param id ID for this new Intent object. | ||
19 | + * @param src The source transponder port. | ||
20 | + * @param dst The destination transponder port. | ||
21 | + */ | ||
22 | + public OpticalConnectivityIntent(ApplicationId appId, ConnectPoint src, ConnectPoint dst) { | ||
23 | + super(id(OpticalConnectivityIntent.class, src, dst), | ||
24 | + appId, null); | ||
25 | + this.src = src; | ||
26 | + this.dst = dst; | ||
27 | + } | ||
28 | + | ||
29 | + /** | ||
30 | + * Constructor for serializer. | ||
31 | + */ | ||
32 | + protected OpticalConnectivityIntent() { | ||
33 | + super(); | ||
34 | + this.src = null; | ||
35 | + this.dst = null; | ||
36 | + } | ||
37 | + | ||
38 | + /** | ||
39 | + * Gets source transponder port. | ||
40 | + * | ||
41 | + * @return The source transponder port. | ||
42 | + */ | ||
43 | + public ConnectPoint getSrcConnectPoint() { | ||
44 | + return src; | ||
45 | + } | ||
46 | + | ||
47 | + /** | ||
48 | + * Gets destination transponder port. | ||
49 | + * | ||
50 | + * @return The source transponder port. | ||
51 | + */ | ||
52 | + public ConnectPoint getDst() { | ||
53 | + return dst; | ||
54 | + } | ||
55 | +} |
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import java.util.Collection; | ||
4 | + | ||
5 | +import org.onlab.onos.ApplicationId; | ||
6 | +import org.onlab.onos.net.ConnectPoint; | ||
7 | +import org.onlab.onos.net.Link; | ||
8 | +import org.onlab.onos.net.NetworkResource; | ||
9 | +import org.onlab.onos.net.Path; | ||
10 | + | ||
11 | +import com.google.common.base.MoreObjects; | ||
12 | +import com.google.common.collect.ImmutableSet; | ||
13 | + | ||
14 | +public class OpticalPathIntent extends Intent { | ||
15 | + | ||
16 | + private final ConnectPoint src; | ||
17 | + private final ConnectPoint dst; | ||
18 | + private final Path path; | ||
19 | + | ||
20 | + | ||
21 | + public OpticalPathIntent(ApplicationId appId, | ||
22 | + ConnectPoint src, | ||
23 | + ConnectPoint dst, | ||
24 | + Path path) { | ||
25 | + super(id(OpticalPathIntent.class, src, dst), | ||
26 | + appId, | ||
27 | + ImmutableSet.<NetworkResource>copyOf(path.links())); | ||
28 | + this.src = src; | ||
29 | + this.dst = dst; | ||
30 | + this.path = path; | ||
31 | + } | ||
32 | + | ||
33 | + protected OpticalPathIntent() { | ||
34 | + this.src = null; | ||
35 | + this.dst = null; | ||
36 | + this.path = null; | ||
37 | + } | ||
38 | + | ||
39 | + public ConnectPoint src() { | ||
40 | + return src; | ||
41 | + } | ||
42 | + | ||
43 | + public ConnectPoint dst() { | ||
44 | + return dst; | ||
45 | + } | ||
46 | + | ||
47 | + public Path path() { | ||
48 | + return path; | ||
49 | + } | ||
50 | + | ||
51 | + @Override | ||
52 | + public boolean isInstallable() { | ||
53 | + return true; | ||
54 | + } | ||
55 | + | ||
56 | + @Override | ||
57 | + public String toString() { | ||
58 | + return MoreObjects.toStringHelper(getClass()) | ||
59 | + .add("id", id()) | ||
60 | + .add("ingressPort", src) | ||
61 | + .add("egressPort", dst) | ||
62 | + .add("path", path) | ||
63 | + .toString(); | ||
64 | + } | ||
65 | + | ||
66 | + public Collection<Link> requiredLinks() { | ||
67 | + return path.links(); | ||
68 | + } | ||
69 | +} |
... | @@ -3,6 +3,21 @@ package org.onlab.onos.net.resource; | ... | @@ -3,6 +3,21 @@ package org.onlab.onos.net.resource; |
3 | /** | 3 | /** |
4 | * Representation of allocated bandwidth resource. | 4 | * Representation of allocated bandwidth resource. |
5 | */ | 5 | */ |
6 | -public interface BandwidthResourceAllocation extends BandwidthResourceRequest { | 6 | +public class BandwidthResourceAllocation extends BandwidthResourceRequest |
7 | + implements ResourceAllocation { | ||
7 | 8 | ||
9 | + @Override | ||
10 | + public ResourceType type() { | ||
11 | + return ResourceType.BANDWIDTH; | ||
12 | + } | ||
13 | + | ||
14 | + /** | ||
15 | + * Creates a new {@link BandwidthResourceAllocation} with {@link Bandwidth} | ||
16 | + * object. | ||
17 | + * | ||
18 | + * @param bandwidth allocated bandwidth | ||
19 | + */ | ||
20 | + public BandwidthResourceAllocation(Bandwidth bandwidth) { | ||
21 | + super(bandwidth); | ||
22 | + } | ||
8 | } | 23 | } | ... | ... |
... | @@ -3,11 +3,39 @@ package org.onlab.onos.net.resource; | ... | @@ -3,11 +3,39 @@ package org.onlab.onos.net.resource; |
3 | /** | 3 | /** |
4 | * Representation of a request for bandwidth resource. | 4 | * Representation of a request for bandwidth resource. |
5 | */ | 5 | */ |
6 | -public interface BandwidthResourceRequest { | 6 | +public class BandwidthResourceRequest implements ResourceRequest { |
7 | + private final Bandwidth bandwidth; | ||
8 | + | ||
9 | + /** | ||
10 | + * Creates a new {@link BandwidthResourceRequest} with {@link Bandwidth} | ||
11 | + * object. | ||
12 | + * | ||
13 | + * @param bandwidth {@link Bandwidth} object to be requested | ||
14 | + */ | ||
15 | + public BandwidthResourceRequest(Bandwidth bandwidth) { | ||
16 | + this.bandwidth = bandwidth; | ||
17 | + } | ||
18 | + | ||
19 | + /** | ||
20 | + * Creates a new {@link BandwidthResourceRequest} with bandwidth value. | ||
21 | + * | ||
22 | + * @param bandwidth bandwidth value to be requested | ||
23 | + */ | ||
24 | + public BandwidthResourceRequest(double bandwidth) { | ||
25 | + this.bandwidth = Bandwidth.valueOf(bandwidth); | ||
26 | + } | ||
27 | + | ||
7 | /** | 28 | /** |
8 | * Returns the bandwidth resource. | 29 | * Returns the bandwidth resource. |
9 | * | 30 | * |
10 | * @return the bandwidth resource | 31 | * @return the bandwidth resource |
11 | */ | 32 | */ |
12 | - Bandwidth bandwidth(); | 33 | + public Bandwidth bandwidth() { |
34 | + return bandwidth; | ||
35 | + } | ||
36 | + | ||
37 | + @Override | ||
38 | + public ResourceType type() { | ||
39 | + return ResourceType.BANDWIDTH; | ||
40 | + } | ||
13 | } | 41 | } | ... | ... |
1 | +package org.onlab.onos.net.resource; | ||
2 | + | ||
3 | +import java.util.Collection; | ||
4 | +import java.util.HashSet; | ||
5 | +import java.util.Set; | ||
6 | + | ||
7 | +import org.onlab.onos.net.Link; | ||
8 | +import org.onlab.onos.net.intent.IntentId; | ||
9 | + | ||
10 | +import com.google.common.collect.ImmutableSet; | ||
11 | + | ||
12 | +/** | ||
13 | + * Implementation of {@link LinkResourceRequest}. | ||
14 | + */ | ||
15 | +public final class DefaultLinkResourceRequest implements LinkResourceRequest { | ||
16 | + | ||
17 | + private final IntentId intentId; | ||
18 | + private final Collection<Link> links; | ||
19 | + private final Set<ResourceRequest> resources; | ||
20 | + | ||
21 | + /** | ||
22 | + * Creates a new link resource request with the given ID, links, and | ||
23 | + * resource requests. | ||
24 | + * | ||
25 | + * @param intentId intent ID related to this request | ||
26 | + * @param links a set of links for the request | ||
27 | + * @param resources a set of resources to be requested | ||
28 | + */ | ||
29 | + private DefaultLinkResourceRequest(IntentId intentId, | ||
30 | + Collection<Link> links, | ||
31 | + Set<ResourceRequest> resources) { | ||
32 | + this.intentId = intentId; | ||
33 | + this.links = ImmutableSet.copyOf(links); | ||
34 | + this.resources = ImmutableSet.copyOf(resources); | ||
35 | + } | ||
36 | + | ||
37 | + | ||
38 | + @Override | ||
39 | + public ResourceType type() { | ||
40 | + return null; | ||
41 | + } | ||
42 | + | ||
43 | + @Override | ||
44 | + public IntentId intendId() { | ||
45 | + return intentId; | ||
46 | + } | ||
47 | + | ||
48 | + @Override | ||
49 | + public Collection<Link> links() { | ||
50 | + return links; | ||
51 | + } | ||
52 | + | ||
53 | + @Override | ||
54 | + public Set<ResourceRequest> resources() { | ||
55 | + return resources; | ||
56 | + } | ||
57 | + | ||
58 | + /** | ||
59 | + * Returns builder of link resource request. | ||
60 | + * | ||
61 | + * @param intentId intent ID related to this request | ||
62 | + * @param links a set of links for the request | ||
63 | + * @return builder of link resource request | ||
64 | + */ | ||
65 | + public static LinkResourceRequest.Builder builder( | ||
66 | + IntentId intentId, Collection<Link> links) { | ||
67 | + return new Builder(intentId, links); | ||
68 | + } | ||
69 | + | ||
70 | + /** | ||
71 | + * Builder of link resource request. | ||
72 | + */ | ||
73 | + public static final class Builder implements LinkResourceRequest.Builder { | ||
74 | + private IntentId intentId; | ||
75 | + private Collection<Link> links; | ||
76 | + private Set<ResourceRequest> resources; | ||
77 | + | ||
78 | + /** | ||
79 | + * Creates a new link resource request. | ||
80 | + * | ||
81 | + * @param intentId intent ID related to this request | ||
82 | + * @param links a set of links for the request | ||
83 | + */ | ||
84 | + private Builder(IntentId intentId, Collection<Link> links) { | ||
85 | + this.intentId = intentId; | ||
86 | + this.links = links; | ||
87 | + this.resources = new HashSet<>(); | ||
88 | + } | ||
89 | + | ||
90 | + /** | ||
91 | + * Adds lambda request. | ||
92 | + * | ||
93 | + * @return self | ||
94 | + */ | ||
95 | + @Override | ||
96 | + public Builder addLambdaRequest() { | ||
97 | + resources.add(new LambdaResourceRequest()); | ||
98 | + return this; | ||
99 | + } | ||
100 | + | ||
101 | + /** | ||
102 | + * Adds bandwidth request with bandwidth value. | ||
103 | + * | ||
104 | + * @param bandwidth bandwidth value to be requested | ||
105 | + * @return self | ||
106 | + */ | ||
107 | + @Override | ||
108 | + public Builder addBandwidthRequest(double bandwidth) { | ||
109 | + resources.add(new BandwidthResourceRequest(bandwidth)); | ||
110 | + return this; | ||
111 | + } | ||
112 | + | ||
113 | + /** | ||
114 | + * Returns link resource request. | ||
115 | + * | ||
116 | + * @return link resource request | ||
117 | + */ | ||
118 | + @Override | ||
119 | + public LinkResourceRequest build() { | ||
120 | + return new DefaultLinkResourceRequest(intentId, links, resources); | ||
121 | + } | ||
122 | + } | ||
123 | + | ||
124 | +} |
... | @@ -3,11 +3,31 @@ package org.onlab.onos.net.resource; | ... | @@ -3,11 +3,31 @@ package org.onlab.onos.net.resource; |
3 | /** | 3 | /** |
4 | * Representation of allocated lambda resource. | 4 | * Representation of allocated lambda resource. |
5 | */ | 5 | */ |
6 | -public interface LambdaResourceAllocation extends LambdaResourceRequest { | 6 | +public class LambdaResourceAllocation extends LambdaResourceRequest |
7 | + implements ResourceAllocation { | ||
8 | + private final Lambda lambda; | ||
9 | + | ||
10 | + @Override | ||
11 | + public ResourceType type() { | ||
12 | + return ResourceType.LAMBDA; | ||
13 | + } | ||
14 | + | ||
15 | + /** | ||
16 | + * Creates a new {@link LambdaResourceAllocation} with {@link Lambda} | ||
17 | + * object. | ||
18 | + * | ||
19 | + * @param lambda allocated lambda | ||
20 | + */ | ||
21 | + public LambdaResourceAllocation(Lambda lambda) { | ||
22 | + this.lambda = lambda; | ||
23 | + } | ||
24 | + | ||
7 | /** | 25 | /** |
8 | * Returns the lambda resource. | 26 | * Returns the lambda resource. |
9 | * | 27 | * |
10 | * @return the lambda resource | 28 | * @return the lambda resource |
11 | */ | 29 | */ |
12 | - Lambda lambda(); | 30 | + public Lambda lambda() { |
31 | + return lambda; | ||
32 | + } | ||
13 | } | 33 | } | ... | ... |
... | @@ -3,6 +3,11 @@ package org.onlab.onos.net.resource; | ... | @@ -3,6 +3,11 @@ package org.onlab.onos.net.resource; |
3 | /** | 3 | /** |
4 | * Representation of a request for lambda resource. | 4 | * Representation of a request for lambda resource. |
5 | */ | 5 | */ |
6 | -public interface LambdaResourceRequest { | 6 | +public class LambdaResourceRequest implements ResourceRequest { |
7 | + | ||
8 | + @Override | ||
9 | + public ResourceType type() { | ||
10 | + return ResourceType.LAMBDA; | ||
11 | + } | ||
7 | 12 | ||
8 | } | 13 | } | ... | ... |
1 | package org.onlab.onos.net.resource; | 1 | package org.onlab.onos.net.resource; |
2 | 2 | ||
3 | +import java.util.Set; | ||
4 | + | ||
3 | import org.onlab.onos.net.Link; | 5 | import org.onlab.onos.net.Link; |
4 | 6 | ||
5 | /** | 7 | /** |
... | @@ -12,5 +14,5 @@ public interface LinkResourceAllocations extends LinkResourceRequest { | ... | @@ -12,5 +14,5 @@ public interface LinkResourceAllocations extends LinkResourceRequest { |
12 | * @param link the target link | 14 | * @param link the target link |
13 | * @return allocated resource for the link | 15 | * @return allocated resource for the link |
14 | */ | 16 | */ |
15 | - ResourceAllocation getResourceAllocation(Link link); | 17 | + Set<ResourceAllocation> getResourceAllocation(Link link); |
16 | } | 18 | } | ... | ... |
... | @@ -31,4 +31,31 @@ public interface LinkResourceRequest extends ResourceRequest { | ... | @@ -31,4 +31,31 @@ public interface LinkResourceRequest extends ResourceRequest { |
31 | * @return the set of resource requests | 31 | * @return the set of resource requests |
32 | */ | 32 | */ |
33 | Set<ResourceRequest> resources(); | 33 | Set<ResourceRequest> resources(); |
34 | + | ||
35 | + /** | ||
36 | + * Builder of link resource request. | ||
37 | + */ | ||
38 | + interface Builder { | ||
39 | + /** | ||
40 | + * Adds lambda request. | ||
41 | + * | ||
42 | + * @return self | ||
43 | + */ | ||
44 | + public Builder addLambdaRequest(); | ||
45 | + | ||
46 | + /** | ||
47 | + * Adds bandwidth request with bandwidth value. | ||
48 | + * | ||
49 | + * @param bandwidth bandwidth value to be requested | ||
50 | + * @return self | ||
51 | + */ | ||
52 | + public Builder addBandwidthRequest(double bandwidth); | ||
53 | + | ||
54 | + /** | ||
55 | + * Returns link resource request. | ||
56 | + * | ||
57 | + * @return link resource request | ||
58 | + */ | ||
59 | + public LinkResourceRequest build(); | ||
60 | + } | ||
34 | } | 61 | } | ... | ... |
... | @@ -31,6 +31,14 @@ public interface LinkResourceService { | ... | @@ -31,6 +31,14 @@ public interface LinkResourceService { |
31 | Iterable<LinkResourceAllocations> getAllocations(); | 31 | Iterable<LinkResourceAllocations> getAllocations(); |
32 | 32 | ||
33 | /** | 33 | /** |
34 | + * Returns the resources allocated for an Intent. | ||
35 | + * | ||
36 | + * @param intentId the target Intent's id | ||
37 | + * @return allocated resources for Intent | ||
38 | + */ | ||
39 | + LinkResourceAllocations getAllocations(IntentId intentId); | ||
40 | + | ||
41 | + /** | ||
34 | * Returns all allocated resources to given link. | 42 | * Returns all allocated resources to given link. |
35 | * | 43 | * |
36 | * @param link a target link | 44 | * @param link a target link | ... | ... |
... | @@ -4,5 +4,11 @@ package org.onlab.onos.net.resource; | ... | @@ -4,5 +4,11 @@ package org.onlab.onos.net.resource; |
4 | * Abstraction of resource request. | 4 | * Abstraction of resource request. |
5 | */ | 5 | */ |
6 | public interface ResourceRequest { | 6 | public interface ResourceRequest { |
7 | + /** | ||
8 | + * Returns the resource type. | ||
9 | + * | ||
10 | + * @return the resource type | ||
11 | + */ | ||
12 | + ResourceType type(); | ||
7 | 13 | ||
8 | } | 14 | } | ... | ... |
1 | +/* | ||
2 | + * Licensed to the Apache Software Foundation (ASF) under one | ||
3 | + * or more contributor license agreements. See the NOTICE file | ||
4 | + * distributed with this work for additional information | ||
5 | + * regarding copyright ownership. The ASF licenses this file | ||
6 | + * to you under the Apache License, Version 2.0 (the | ||
7 | + * "License"); you may not use this file except in compliance | ||
8 | + * with the License. You may obtain a copy of the License at | ||
9 | + * | ||
10 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + * | ||
12 | + * Unless required by applicable law or agreed to in writing, | ||
13 | + * software distributed under the License is distributed on an | ||
14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
15 | + * KIND, either express or implied. See the License for the | ||
16 | + * specific language governing permissions and limitations | ||
17 | + * under the License. | ||
18 | + */ | ||
19 | +package org.onlab.onos.codec; | ||
20 | + | ||
21 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
22 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
23 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
24 | +import com.google.common.collect.ImmutableList; | ||
25 | +import org.junit.Test; | ||
26 | + | ||
27 | +import java.util.List; | ||
28 | +import java.util.Objects; | ||
29 | + | ||
30 | +import static org.junit.Assert.assertEquals; | ||
31 | + | ||
32 | +/** | ||
33 | + * Test of the base JSON codec abstraction. | ||
34 | + */ | ||
35 | +public class JsonCodecTest { | ||
36 | + | ||
37 | + private static class Foo { | ||
38 | + final String name; | ||
39 | + | ||
40 | + Foo(String name) { | ||
41 | + this.name = name; | ||
42 | + } | ||
43 | + | ||
44 | + @Override | ||
45 | + public int hashCode() { | ||
46 | + return Objects.hash(name); | ||
47 | + } | ||
48 | + | ||
49 | + @Override | ||
50 | + public boolean equals(Object obj) { | ||
51 | + if (this == obj) { | ||
52 | + return true; | ||
53 | + } | ||
54 | + if (obj == null || getClass() != obj.getClass()) { | ||
55 | + return false; | ||
56 | + } | ||
57 | + final Foo other = (Foo) obj; | ||
58 | + return Objects.equals(this.name, other.name); | ||
59 | + } | ||
60 | + } | ||
61 | + | ||
62 | + private static class FooCodec extends JsonCodec<Foo> { | ||
63 | + @Override | ||
64 | + public ObjectNode encode(Foo entity, ObjectMapper mapper) { | ||
65 | + return mapper.createObjectNode().put("name", entity.name); | ||
66 | + } | ||
67 | + | ||
68 | + @Override | ||
69 | + public Foo decode(ObjectNode json) { | ||
70 | + return new Foo(json.get("name").asText()); | ||
71 | + } | ||
72 | + } | ||
73 | + | ||
74 | + @Test | ||
75 | + public void encode() { | ||
76 | + Foo f1 = new Foo("foo"); | ||
77 | + Foo f2 = new Foo("bar"); | ||
78 | + FooCodec codec = new FooCodec(); | ||
79 | + ImmutableList<Foo> entities = ImmutableList.of(f1, f2); | ||
80 | + ArrayNode json = codec.encode(entities, new ObjectMapper()); | ||
81 | + List<Foo> foos = codec.decode(json); | ||
82 | + assertEquals("incorrect encode/decode", entities, foos); | ||
83 | + } | ||
84 | + | ||
85 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -2,11 +2,15 @@ package org.onlab.onos.net.flow.impl; | ... | @@ -2,11 +2,15 @@ package org.onlab.onos.net.flow.impl; |
2 | 2 | ||
3 | import static com.google.common.base.Preconditions.checkNotNull; | 3 | import static com.google.common.base.Preconditions.checkNotNull; |
4 | import static org.slf4j.LoggerFactory.getLogger; | 4 | import static org.slf4j.LoggerFactory.getLogger; |
5 | +import static org.onlab.util.Tools.namedThreads; | ||
5 | 6 | ||
6 | import java.util.List; | 7 | import java.util.List; |
7 | import java.util.Map; | 8 | import java.util.Map; |
9 | +import java.util.Set; | ||
8 | import java.util.concurrent.CancellationException; | 10 | import java.util.concurrent.CancellationException; |
9 | import java.util.concurrent.ExecutionException; | 11 | import java.util.concurrent.ExecutionException; |
12 | +import java.util.concurrent.ExecutorService; | ||
13 | +import java.util.concurrent.Executors; | ||
10 | import java.util.concurrent.Future; | 14 | import java.util.concurrent.Future; |
11 | import java.util.concurrent.TimeUnit; | 15 | import java.util.concurrent.TimeUnit; |
12 | import java.util.concurrent.TimeoutException; | 16 | import java.util.concurrent.TimeoutException; |
... | @@ -30,7 +34,9 @@ import org.onlab.onos.net.flow.FlowEntry; | ... | @@ -30,7 +34,9 @@ import org.onlab.onos.net.flow.FlowEntry; |
30 | import org.onlab.onos.net.flow.FlowRule; | 34 | import org.onlab.onos.net.flow.FlowRule; |
31 | import org.onlab.onos.net.flow.FlowRuleBatchEntry; | 35 | import org.onlab.onos.net.flow.FlowRuleBatchEntry; |
32 | import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | 36 | import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; |
37 | +import org.onlab.onos.net.flow.FlowRuleBatchEvent; | ||
33 | import org.onlab.onos.net.flow.FlowRuleBatchOperation; | 38 | import org.onlab.onos.net.flow.FlowRuleBatchOperation; |
39 | +import org.onlab.onos.net.flow.FlowRuleBatchRequest; | ||
34 | import org.onlab.onos.net.flow.FlowRuleEvent; | 40 | import org.onlab.onos.net.flow.FlowRuleEvent; |
35 | import org.onlab.onos.net.flow.FlowRuleListener; | 41 | import org.onlab.onos.net.flow.FlowRuleListener; |
36 | import org.onlab.onos.net.flow.FlowRuleProvider; | 42 | import org.onlab.onos.net.flow.FlowRuleProvider; |
... | @@ -47,6 +53,9 @@ import com.google.common.collect.ArrayListMultimap; | ... | @@ -47,6 +53,9 @@ import com.google.common.collect.ArrayListMultimap; |
47 | import com.google.common.collect.Lists; | 53 | import com.google.common.collect.Lists; |
48 | import com.google.common.collect.Maps; | 54 | import com.google.common.collect.Maps; |
49 | import com.google.common.collect.Multimap; | 55 | import com.google.common.collect.Multimap; |
56 | +import com.google.common.collect.Sets; | ||
57 | +import com.google.common.util.concurrent.Futures; | ||
58 | +import com.google.common.util.concurrent.ListenableFuture; | ||
50 | 59 | ||
51 | /** | 60 | /** |
52 | * Provides implementation of the flow NB & SB APIs. | 61 | * Provides implementation of the flow NB & SB APIs. |
... | @@ -67,6 +76,9 @@ public class FlowRuleManager | ... | @@ -67,6 +76,9 @@ public class FlowRuleManager |
67 | 76 | ||
68 | private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate(); | 77 | private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate(); |
69 | 78 | ||
79 | + private final ExecutorService futureListeners = | ||
80 | + Executors.newCachedThreadPool(namedThreads("provider-future-listeners")); | ||
81 | + | ||
70 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 82 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
71 | protected FlowRuleStore store; | 83 | protected FlowRuleStore store; |
72 | 84 | ||
... | @@ -85,6 +97,8 @@ public class FlowRuleManager | ... | @@ -85,6 +97,8 @@ public class FlowRuleManager |
85 | 97 | ||
86 | @Deactivate | 98 | @Deactivate |
87 | public void deactivate() { | 99 | public void deactivate() { |
100 | + futureListeners.shutdownNow(); | ||
101 | + | ||
88 | store.unsetDelegate(delegate); | 102 | store.unsetDelegate(delegate); |
89 | eventDispatcher.removeSink(FlowRuleEvent.class); | 103 | eventDispatcher.removeSink(FlowRuleEvent.class); |
90 | log.info("Stopped"); | 104 | log.info("Stopped"); |
... | @@ -104,14 +118,7 @@ public class FlowRuleManager | ... | @@ -104,14 +118,7 @@ public class FlowRuleManager |
104 | public void applyFlowRules(FlowRule... flowRules) { | 118 | public void applyFlowRules(FlowRule... flowRules) { |
105 | for (int i = 0; i < flowRules.length; i++) { | 119 | for (int i = 0; i < flowRules.length; i++) { |
106 | FlowRule f = flowRules[i]; | 120 | FlowRule f = flowRules[i]; |
107 | - boolean local = store.storeFlowRule(f); | 121 | + store.storeFlowRule(f); |
108 | - if (local) { | ||
109 | - // TODO: aggregate all local rules and push down once? | ||
110 | - applyFlowRulesToProviders(f); | ||
111 | - eventDispatcher.post( | ||
112 | - new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADD_REQUESTED, f)); | ||
113 | - | ||
114 | - } | ||
115 | } | 122 | } |
116 | } | 123 | } |
117 | 124 | ||
... | @@ -135,13 +142,7 @@ public class FlowRuleManager | ... | @@ -135,13 +142,7 @@ public class FlowRuleManager |
135 | FlowRule f; | 142 | FlowRule f; |
136 | for (int i = 0; i < flowRules.length; i++) { | 143 | for (int i = 0; i < flowRules.length; i++) { |
137 | f = flowRules[i]; | 144 | f = flowRules[i]; |
138 | - boolean local = store.deleteFlowRule(f); | 145 | + store.deleteFlowRule(f); |
139 | - if (local) { | ||
140 | - // TODO: aggregate all local rules and push down once? | ||
141 | - removeFlowRulesFromProviders(f); | ||
142 | - eventDispatcher.post( | ||
143 | - new FlowRuleEvent(FlowRuleEvent.Type.RULE_REMOVE_REQUESTED, f)); | ||
144 | - } | ||
145 | } | 146 | } |
146 | } | 147 | } |
147 | 148 | ||
... | @@ -185,33 +186,21 @@ public class FlowRuleManager | ... | @@ -185,33 +186,21 @@ public class FlowRuleManager |
185 | @Override | 186 | @Override |
186 | public Future<CompletedBatchOperation> applyBatch( | 187 | public Future<CompletedBatchOperation> applyBatch( |
187 | FlowRuleBatchOperation batch) { | 188 | FlowRuleBatchOperation batch) { |
188 | - Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches = | 189 | + Multimap<DeviceId, FlowRuleBatchEntry> perDeviceBatches = |
189 | ArrayListMultimap.create(); | 190 | ArrayListMultimap.create(); |
190 | List<Future<CompletedBatchOperation>> futures = Lists.newArrayList(); | 191 | List<Future<CompletedBatchOperation>> futures = Lists.newArrayList(); |
191 | for (FlowRuleBatchEntry fbe : batch.getOperations()) { | 192 | for (FlowRuleBatchEntry fbe : batch.getOperations()) { |
192 | final FlowRule f = fbe.getTarget(); | 193 | final FlowRule f = fbe.getTarget(); |
193 | - final Device device = deviceService.getDevice(f.deviceId()); | 194 | + perDeviceBatches.put(f.deviceId(), fbe); |
194 | - final FlowRuleProvider frp = getProvider(device.providerId()); | ||
195 | - batches.put(frp, fbe); | ||
196 | - switch (fbe.getOperator()) { | ||
197 | - case ADD: | ||
198 | - store.storeFlowRule(f); | ||
199 | - break; | ||
200 | - case REMOVE: | ||
201 | - store.deleteFlowRule(f); | ||
202 | - break; | ||
203 | - case MODIFY: | ||
204 | - default: | ||
205 | - log.error("Batch operation type {} unsupported.", fbe.getOperator()); | ||
206 | } | 195 | } |
207 | - } | 196 | + |
208 | - for (FlowRuleProvider provider : batches.keySet()) { | 197 | + for (DeviceId deviceId : perDeviceBatches.keySet()) { |
209 | FlowRuleBatchOperation b = | 198 | FlowRuleBatchOperation b = |
210 | - new FlowRuleBatchOperation(batches.get(provider)); | 199 | + new FlowRuleBatchOperation(perDeviceBatches.get(deviceId)); |
211 | - Future<CompletedBatchOperation> future = provider.executeBatch(b); | 200 | + Future<CompletedBatchOperation> future = store.storeBatch(b); |
212 | futures.add(future); | 201 | futures.add(future); |
213 | } | 202 | } |
214 | - return new FlowRuleBatchFuture(futures, batches); | 203 | + return new FlowRuleBatchFuture(futures, perDeviceBatches); |
215 | } | 204 | } |
216 | 205 | ||
217 | @Override | 206 | @Override |
... | @@ -324,6 +313,7 @@ public class FlowRuleManager | ... | @@ -324,6 +313,7 @@ public class FlowRuleManager |
324 | post(event); | 313 | post(event); |
325 | } | 314 | } |
326 | } else { | 315 | } else { |
316 | + log.info("Removing flow rules...."); | ||
327 | removeFlowRules(flowEntry); | 317 | removeFlowRules(flowEntry); |
328 | } | 318 | } |
329 | 319 | ||
... | @@ -391,21 +381,48 @@ public class FlowRuleManager | ... | @@ -391,21 +381,48 @@ public class FlowRuleManager |
391 | 381 | ||
392 | // Store delegate to re-post events emitted from the store. | 382 | // Store delegate to re-post events emitted from the store. |
393 | private class InternalStoreDelegate implements FlowRuleStoreDelegate { | 383 | private class InternalStoreDelegate implements FlowRuleStoreDelegate { |
384 | + // TODO: Right now we only dispatch events at individual flowEntry level. | ||
385 | + // It may be more efficient for also dispatch events as a batch. | ||
394 | @Override | 386 | @Override |
395 | - public void notify(FlowRuleEvent event) { | 387 | + public void notify(FlowRuleBatchEvent event) { |
388 | + final FlowRuleBatchRequest request = event.subject(); | ||
396 | switch (event.type()) { | 389 | switch (event.type()) { |
397 | - case RULE_ADD_REQUESTED: | 390 | + case BATCH_OPERATION_REQUESTED: |
398 | - applyFlowRulesToProviders(event.subject()); | 391 | + for (FlowEntry entry : request.toAdd()) { |
399 | - break; | 392 | + eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADD_REQUESTED, entry)); |
400 | - case RULE_REMOVE_REQUESTED: | 393 | + } |
401 | - removeFlowRulesFromProviders(event.subject()); | 394 | + for (FlowEntry entry : request.toRemove()) { |
402 | - break; | 395 | + eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_REMOVE_REQUESTED, entry)); |
396 | + } | ||
397 | + // FIXME: what about op.equals(FlowRuleOperation.MODIFY) ? | ||
398 | + | ||
399 | + FlowRuleBatchOperation batchOperation = request.asBatchOperation(); | ||
400 | + | ||
401 | + FlowRuleProvider flowRuleProvider = | ||
402 | + getProvider(batchOperation.getOperations().get(0).getTarget().deviceId()); | ||
403 | + final ListenableFuture<CompletedBatchOperation> result = | ||
404 | + flowRuleProvider.executeBatch(batchOperation); | ||
405 | + result.addListener(new Runnable() { | ||
406 | + @Override | ||
407 | + public void run() { | ||
408 | + store.batchOperationComplete(FlowRuleBatchEvent.completed(request, | ||
409 | + Futures.getUnchecked(result))); | ||
410 | + } | ||
411 | + }, futureListeners); | ||
403 | 412 | ||
404 | - case RULE_ADDED: | 413 | + break; |
405 | - case RULE_REMOVED: | 414 | + case BATCH_OPERATION_COMPLETED: |
406 | - case RULE_UPDATED: | 415 | + Set<FlowEntry> failedItems = event.result().failedItems(); |
407 | - // only dispatch events related to switch | 416 | + for (FlowEntry entry : request.toAdd()) { |
408 | - eventDispatcher.post(event); | 417 | + if (!failedItems.contains(entry)) { |
418 | + eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADDED, entry)); | ||
419 | + } | ||
420 | + } | ||
421 | + for (FlowEntry entry : request.toRemove()) { | ||
422 | + if (!failedItems.contains(entry)) { | ||
423 | + eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_REMOVED, entry)); | ||
424 | + } | ||
425 | + } | ||
409 | break; | 426 | break; |
410 | default: | 427 | default: |
411 | break; | 428 | break; |
... | @@ -413,18 +430,15 @@ public class FlowRuleManager | ... | @@ -413,18 +430,15 @@ public class FlowRuleManager |
413 | } | 430 | } |
414 | } | 431 | } |
415 | 432 | ||
416 | - private class FlowRuleBatchFuture | 433 | + private class FlowRuleBatchFuture implements Future<CompletedBatchOperation> { |
417 | - implements Future<CompletedBatchOperation> { | ||
418 | 434 | ||
419 | private final List<Future<CompletedBatchOperation>> futures; | 435 | private final List<Future<CompletedBatchOperation>> futures; |
420 | - private final Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches; | 436 | + private final Multimap<DeviceId, FlowRuleBatchEntry> batches; |
421 | private final AtomicReference<BatchState> state; | 437 | private final AtomicReference<BatchState> state; |
422 | private CompletedBatchOperation overall; | 438 | private CompletedBatchOperation overall; |
423 | 439 | ||
424 | - | ||
425 | - | ||
426 | public FlowRuleBatchFuture(List<Future<CompletedBatchOperation>> futures, | 440 | public FlowRuleBatchFuture(List<Future<CompletedBatchOperation>> futures, |
427 | - Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches) { | 441 | + Multimap<DeviceId, FlowRuleBatchEntry> batches) { |
428 | this.futures = futures; | 442 | this.futures = futures; |
429 | this.batches = batches; | 443 | this.batches = batches; |
430 | state = new AtomicReference<FlowRuleManager.BatchState>(); | 444 | state = new AtomicReference<FlowRuleManager.BatchState>(); |
... | @@ -466,7 +480,7 @@ public class FlowRuleManager | ... | @@ -466,7 +480,7 @@ public class FlowRuleManager |
466 | } | 480 | } |
467 | 481 | ||
468 | boolean success = true; | 482 | boolean success = true; |
469 | - List<FlowEntry> failed = Lists.newLinkedList(); | 483 | + Set<FlowEntry> failed = Sets.newHashSet(); |
470 | CompletedBatchOperation completed; | 484 | CompletedBatchOperation completed; |
471 | for (Future<CompletedBatchOperation> future : futures) { | 485 | for (Future<CompletedBatchOperation> future : futures) { |
472 | completed = future.get(); | 486 | completed = future.get(); |
... | @@ -486,7 +500,7 @@ public class FlowRuleManager | ... | @@ -486,7 +500,7 @@ public class FlowRuleManager |
486 | return overall; | 500 | return overall; |
487 | } | 501 | } |
488 | boolean success = true; | 502 | boolean success = true; |
489 | - List<FlowEntry> failed = Lists.newLinkedList(); | 503 | + Set<FlowEntry> failed = Sets.newHashSet(); |
490 | CompletedBatchOperation completed; | 504 | CompletedBatchOperation completed; |
491 | long start = System.nanoTime(); | 505 | long start = System.nanoTime(); |
492 | long end = start + unit.toNanos(timeout); | 506 | long end = start + unit.toNanos(timeout); |
... | @@ -500,7 +514,7 @@ public class FlowRuleManager | ... | @@ -500,7 +514,7 @@ public class FlowRuleManager |
500 | return finalizeBatchOperation(success, failed); | 514 | return finalizeBatchOperation(success, failed); |
501 | } | 515 | } |
502 | 516 | ||
503 | - private boolean validateBatchOperation(List<FlowEntry> failed, | 517 | + private boolean validateBatchOperation(Set<FlowEntry> failed, |
504 | CompletedBatchOperation completed) { | 518 | CompletedBatchOperation completed) { |
505 | 519 | ||
506 | if (isCancelled()) { | 520 | if (isCancelled()) { |
... | @@ -522,7 +536,7 @@ public class FlowRuleManager | ... | @@ -522,7 +536,7 @@ public class FlowRuleManager |
522 | } | 536 | } |
523 | 537 | ||
524 | private CompletedBatchOperation finalizeBatchOperation(boolean success, | 538 | private CompletedBatchOperation finalizeBatchOperation(boolean success, |
525 | - List<FlowEntry> failed) { | 539 | + Set<FlowEntry> failed) { |
526 | synchronized (this) { | 540 | synchronized (this) { |
527 | if (!state.compareAndSet(BatchState.STARTED, BatchState.FINISHED)) { | 541 | if (!state.compareAndSet(BatchState.STARTED, BatchState.FINISHED)) { |
528 | if (state.get() == BatchState.FINISHED) { | 542 | if (state.get() == BatchState.FINISHED) { |
... | @@ -545,11 +559,6 @@ public class FlowRuleManager | ... | @@ -545,11 +559,6 @@ public class FlowRuleManager |
545 | store.storeFlowRule(fbe.getTarget()); | 559 | store.storeFlowRule(fbe.getTarget()); |
546 | } | 560 | } |
547 | } | 561 | } |
548 | - | ||
549 | } | 562 | } |
550 | } | 563 | } |
551 | - | ||
552 | - | ||
553 | - | ||
554 | - | ||
555 | } | 564 | } | ... | ... |
core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalConnectivityIntentCompiler.java
0 → 100644
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import static org.slf4j.LoggerFactory.getLogger; | ||
4 | + | ||
5 | +import java.util.ArrayList; | ||
6 | +import java.util.Iterator; | ||
7 | +import java.util.List; | ||
8 | +import java.util.Set; | ||
9 | + | ||
10 | +import org.apache.felix.scr.annotations.Activate; | ||
11 | +import org.apache.felix.scr.annotations.Component; | ||
12 | +import org.apache.felix.scr.annotations.Deactivate; | ||
13 | +import org.apache.felix.scr.annotations.Reference; | ||
14 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
15 | +import org.onlab.onos.CoreService; | ||
16 | +import org.onlab.onos.net.ConnectPoint; | ||
17 | +import org.onlab.onos.net.Link; | ||
18 | +import org.onlab.onos.net.Path; | ||
19 | +import org.onlab.onos.net.intent.Intent; | ||
20 | +import org.onlab.onos.net.intent.IntentCompiler; | ||
21 | +import org.onlab.onos.net.intent.IntentExtensionService; | ||
22 | +import org.onlab.onos.net.intent.OpticalConnectivityIntent; | ||
23 | +import org.onlab.onos.net.intent.OpticalPathIntent; | ||
24 | +import org.onlab.onos.net.provider.ProviderId; | ||
25 | +import org.onlab.onos.net.resource.LinkResourceService; | ||
26 | +import org.onlab.onos.net.topology.LinkWeight; | ||
27 | +import org.onlab.onos.net.topology.PathService; | ||
28 | +import org.onlab.onos.net.topology.Topology; | ||
29 | +import org.onlab.onos.net.topology.TopologyEdge; | ||
30 | +import org.onlab.onos.net.topology.TopologyService; | ||
31 | +import org.slf4j.Logger; | ||
32 | + | ||
33 | +/** | ||
34 | + * Optical compiler for OpticalConnectivityIntent. | ||
35 | + * It firstly computes K-shortest paths in the optical-layer, then choose the optimal one to assign a wavelength. | ||
36 | + * Finally, it generates one or more opticalPathintent(s) with opticalMatchs and opticalActions. | ||
37 | + */ | ||
38 | +@Component(immediate = true) | ||
39 | +public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> { | ||
40 | + | ||
41 | + private final Logger log = getLogger(getClass()); | ||
42 | + private static final ProviderId PID = new ProviderId("core", "org.onlab.onos.core", true); | ||
43 | + | ||
44 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
45 | + protected IntentExtensionService intentManager; | ||
46 | + | ||
47 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
48 | + protected PathService pathService; | ||
49 | + | ||
50 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
51 | + protected TopologyService topologyService; | ||
52 | + | ||
53 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
54 | + protected LinkResourceService resourceService; | ||
55 | + | ||
56 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
57 | + protected CoreService coreService; | ||
58 | + | ||
59 | + @Activate | ||
60 | + public void activate() { | ||
61 | + intentManager.registerCompiler(OpticalConnectivityIntent.class, this); | ||
62 | + } | ||
63 | + | ||
64 | + @Deactivate | ||
65 | + public void deactivate() { | ||
66 | + intentManager.unregisterCompiler(OpticalConnectivityIntent.class); | ||
67 | + } | ||
68 | + | ||
69 | + @Override | ||
70 | + public List<Intent> compile(OpticalConnectivityIntent intent) { | ||
71 | + // TODO: compute multiple paths using the K-shortest path algorithm | ||
72 | + List<Intent> retList = new ArrayList<>(); | ||
73 | + Path path = calculatePath(intent.getSrcConnectPoint(), intent.getDst()); | ||
74 | + if (path == null) { | ||
75 | + return retList; | ||
76 | + } else { | ||
77 | + log.info("the computed lightpath is : {}.", path.toString()); | ||
78 | + } | ||
79 | + | ||
80 | + List<Link> links = new ArrayList<>(); | ||
81 | + // links.add(DefaultEdgeLink.createEdgeLink(intent.getSrcConnectPoint(), true)); | ||
82 | + links.addAll(path.links()); | ||
83 | + //links.add(DefaultEdgeLink.createEdgeLink(intent.getDst(), false)); | ||
84 | + | ||
85 | + // create a new opticalPathIntent | ||
86 | + Intent newIntent = new OpticalPathIntent(intent.appId(), | ||
87 | + intent.getSrcConnectPoint(), | ||
88 | + intent.getDst(), | ||
89 | + path); | ||
90 | + | ||
91 | + retList.add(newIntent); | ||
92 | + | ||
93 | + return retList; | ||
94 | + } | ||
95 | + | ||
96 | + private Path calculatePath(ConnectPoint start, ConnectPoint end) { | ||
97 | + // TODO: support user policies | ||
98 | + Topology topology = topologyService.currentTopology(); | ||
99 | + LinkWeight weight = new LinkWeight() { | ||
100 | + @Override | ||
101 | + public double weight(TopologyEdge edge) { | ||
102 | + boolean isOptical = false; | ||
103 | + | ||
104 | + Link.Type lt = edge.link().type(); | ||
105 | + | ||
106 | + //String t = edge.link().annotations().value("linkType"); | ||
107 | + if (lt == Link.Type.OPTICAL) { | ||
108 | + isOptical = true; | ||
109 | + } | ||
110 | + if (isOptical) { | ||
111 | + return 1; // optical links | ||
112 | + } else { | ||
113 | + return 10000; // packet links | ||
114 | + } | ||
115 | + } | ||
116 | + }; | ||
117 | + | ||
118 | + Set<Path> paths = topologyService.getPaths(topology, | ||
119 | + start.deviceId(), | ||
120 | + end.deviceId(), | ||
121 | + weight); | ||
122 | + | ||
123 | + Iterator<Path> itr = paths.iterator(); | ||
124 | + while (itr.hasNext()) { | ||
125 | + Path path = itr.next(); | ||
126 | + if (path.cost() >= 10000) { | ||
127 | + itr.remove(); | ||
128 | + } | ||
129 | + } | ||
130 | + | ||
131 | + if (paths.isEmpty()) { | ||
132 | + log.info("No optical path found from " + start + " to " + end); | ||
133 | + return null; | ||
134 | + } else { | ||
135 | + return paths.iterator().next(); | ||
136 | + } | ||
137 | + | ||
138 | + } | ||
139 | + | ||
140 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder; | ||
4 | +import static org.slf4j.LoggerFactory.getLogger; | ||
5 | + | ||
6 | +import java.util.List; | ||
7 | + | ||
8 | +import org.apache.felix.scr.annotations.Activate; | ||
9 | +import org.apache.felix.scr.annotations.Component; | ||
10 | +import org.apache.felix.scr.annotations.Deactivate; | ||
11 | +import org.apache.felix.scr.annotations.Reference; | ||
12 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
13 | +import org.onlab.onos.ApplicationId; | ||
14 | +import org.onlab.onos.CoreService; | ||
15 | +import org.onlab.onos.net.ConnectPoint; | ||
16 | +import org.onlab.onos.net.Link; | ||
17 | +import org.onlab.onos.net.flow.DefaultFlowRule; | ||
18 | +import org.onlab.onos.net.flow.DefaultTrafficSelector; | ||
19 | +import org.onlab.onos.net.flow.DefaultTrafficTreatment; | ||
20 | +import org.onlab.onos.net.flow.FlowRule; | ||
21 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry; | ||
22 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | ||
23 | +import org.onlab.onos.net.flow.FlowRuleBatchOperation; | ||
24 | +import org.onlab.onos.net.flow.FlowRuleService; | ||
25 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
26 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
27 | +import org.onlab.onos.net.intent.IntentExtensionService; | ||
28 | +import org.onlab.onos.net.intent.IntentInstaller; | ||
29 | +import org.onlab.onos.net.intent.OpticalPathIntent; | ||
30 | +import org.onlab.onos.net.resource.DefaultLinkResourceRequest; | ||
31 | +import org.onlab.onos.net.resource.Lambda; | ||
32 | +import org.onlab.onos.net.resource.LambdaResourceAllocation; | ||
33 | +import org.onlab.onos.net.resource.LinkResourceAllocations; | ||
34 | +import org.onlab.onos.net.resource.LinkResourceRequest; | ||
35 | +import org.onlab.onos.net.resource.LinkResourceService; | ||
36 | +import org.onlab.onos.net.resource.ResourceAllocation; | ||
37 | +import org.onlab.onos.net.resource.ResourceType; | ||
38 | +import org.onlab.onos.net.topology.TopologyService; | ||
39 | +import org.slf4j.Logger; | ||
40 | + | ||
41 | +import com.google.common.collect.Lists; | ||
42 | + | ||
43 | +/** | ||
44 | + * OpticaliIntentInstaller for optical path intents. | ||
45 | + * It essentially generates optical FlowRules and | ||
46 | + * call the flowRule service to execute them. | ||
47 | + */ | ||
48 | + | ||
49 | +@Component(immediate = true) | ||
50 | +public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIntent> { | ||
51 | + private final Logger log = getLogger(getClass()); | ||
52 | + | ||
53 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
54 | + protected IntentExtensionService intentManager; | ||
55 | + | ||
56 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
57 | + protected FlowRuleService flowRuleService; | ||
58 | + | ||
59 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
60 | + protected CoreService coreService; | ||
61 | + | ||
62 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
63 | + protected TopologyService topologyService; | ||
64 | + | ||
65 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
66 | + protected LinkResourceService resourceService; | ||
67 | + | ||
68 | + private ApplicationId appId; | ||
69 | + | ||
70 | + //final short WAVELENGTH = 80; | ||
71 | + | ||
72 | + @Activate | ||
73 | + public void activate() { | ||
74 | + appId = coreService.registerApplication("org.onlab.onos.net.intent"); | ||
75 | + intentManager.registerInstaller(OpticalPathIntent.class, this); | ||
76 | + } | ||
77 | + | ||
78 | + @Deactivate | ||
79 | + public void deactivate() { | ||
80 | + intentManager.unregisterInstaller(OpticalPathIntent.class); | ||
81 | + } | ||
82 | + | ||
83 | + @Override | ||
84 | + public List<FlowRuleBatchOperation> install(OpticalPathIntent intent) { | ||
85 | + LinkResourceAllocations allocations = assignWavelength(intent); | ||
86 | + | ||
87 | + TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); | ||
88 | + selectorBuilder.matchInport(intent.src().port()); | ||
89 | + | ||
90 | + List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); | ||
91 | + ConnectPoint prev = intent.src(); | ||
92 | + | ||
93 | + //TODO throw exception if the lambda was not assigned successfully | ||
94 | + for (Link link : intent.path().links()) { | ||
95 | + Lambda la = null; | ||
96 | + for (ResourceAllocation allocation : allocations.getResourceAllocation(link)) { | ||
97 | + if (allocation.type() == ResourceType.LAMBDA) { | ||
98 | + la = ((LambdaResourceAllocation) allocation).lambda(); | ||
99 | + break; | ||
100 | + } | ||
101 | + } | ||
102 | + | ||
103 | + if (la == null) { | ||
104 | + log.info("Lambda was not assigned successfully"); | ||
105 | + return null; | ||
106 | + } | ||
107 | + | ||
108 | + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); | ||
109 | + treatmentBuilder.setOutput(link.src().port()); | ||
110 | + treatmentBuilder.setLambda((short) la.toInt()); | ||
111 | + | ||
112 | + FlowRule rule = new DefaultFlowRule(prev.deviceId(), | ||
113 | + selectorBuilder.build(), | ||
114 | + treatmentBuilder.build(), | ||
115 | + 100, | ||
116 | + appId, | ||
117 | + 100, | ||
118 | + true); | ||
119 | + rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)); | ||
120 | + | ||
121 | + prev = link.dst(); | ||
122 | + selectorBuilder.matchInport(link.dst().port()); | ||
123 | + selectorBuilder.matchLambda((short) la.toInt()); | ||
124 | + } | ||
125 | + | ||
126 | + // build the last T port rule | ||
127 | + TrafficTreatment treatmentLast = builder() | ||
128 | + .setOutput(intent.dst().port()).build(); | ||
129 | + FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(), | ||
130 | + selectorBuilder.build(), | ||
131 | + treatmentLast, | ||
132 | + 100, | ||
133 | + appId, | ||
134 | + 100, | ||
135 | + true); | ||
136 | + rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)); | ||
137 | + | ||
138 | + return Lists.newArrayList(new FlowRuleBatchOperation(rules)); | ||
139 | + } | ||
140 | + | ||
141 | + private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) { | ||
142 | + LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(), | ||
143 | + intent.path().links()) | ||
144 | + .addLambdaRequest(); | ||
145 | + LinkResourceAllocations retLambda = resourceService.requestResources(request.build()); | ||
146 | + return retLambda; | ||
147 | + } | ||
148 | + | ||
149 | + /*private Lambda assignWavelength(List<Link> links) { | ||
150 | + // TODO More wavelength assignment algorithm | ||
151 | + int wavenum = 0; | ||
152 | + Iterator<Link> itrlink = links.iterator(); | ||
153 | + for (int i = 1; i <= WAVELENGTH; i++) { | ||
154 | + wavenum = i; | ||
155 | + boolean found = true; | ||
156 | + while (itrlink.hasNext()) { | ||
157 | + Link link = itrlink.next(); | ||
158 | + if (isWavelengthUsed(link, i)) { | ||
159 | + found = false; | ||
160 | + break; | ||
161 | + } | ||
162 | + } | ||
163 | + // First-Fit wavelength assignment algorithm | ||
164 | + if (found) { | ||
165 | + break; | ||
166 | + } | ||
167 | + } | ||
168 | + | ||
169 | + if (wavenum == 0) { | ||
170 | + return null; | ||
171 | + } | ||
172 | + | ||
173 | + Lambda wave = Lambda.valueOf(wavenum); | ||
174 | + return wave; | ||
175 | + } | ||
176 | + | ||
177 | + private boolean isWavelengthUsed(Link link, int i) { | ||
178 | + Iterable<LinkResourceAllocations> wave = resourceService.getAllocations(link); | ||
179 | + for (LinkResourceAllocations ir : wave) { | ||
180 | + //if ir.resources().contains(i) { | ||
181 | + //} | ||
182 | + } | ||
183 | + return false; | ||
184 | + }*/ | ||
185 | + | ||
186 | + @Override | ||
187 | + public List<FlowRuleBatchOperation> uninstall(OpticalPathIntent intent) { | ||
188 | + LinkResourceAllocations allocations = resourceService.getAllocations(intent.id()); | ||
189 | + | ||
190 | + TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); | ||
191 | + selectorBuilder.matchInport(intent.src().port()); | ||
192 | + | ||
193 | + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); | ||
194 | + | ||
195 | + List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); | ||
196 | + ConnectPoint prev = intent.src(); | ||
197 | + | ||
198 | + //TODO throw exception if the lambda was not retrieved successfully | ||
199 | + for (Link link : intent.path().links()) { | ||
200 | + Lambda la = null; | ||
201 | + for (ResourceAllocation allocation : allocations.getResourceAllocation(link)) { | ||
202 | + if (allocation.type() == ResourceType.LAMBDA) { | ||
203 | + la = ((LambdaResourceAllocation) allocation).lambda(); | ||
204 | + break; | ||
205 | + } | ||
206 | + } | ||
207 | + | ||
208 | + if (la == null) { | ||
209 | + log.info("Lambda was not retrieved successfully"); | ||
210 | + return null; | ||
211 | + } | ||
212 | + | ||
213 | + treatmentBuilder.setOutput(link.src().port()); | ||
214 | + treatmentBuilder.setLambda((short) la.toInt()); | ||
215 | + | ||
216 | + FlowRule rule = new DefaultFlowRule(prev.deviceId(), | ||
217 | + selectorBuilder.build(), | ||
218 | + treatmentBuilder.build(), | ||
219 | + 100, | ||
220 | + appId, | ||
221 | + 100, | ||
222 | + true); | ||
223 | + rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule)); | ||
224 | + | ||
225 | + prev = link.dst(); | ||
226 | + selectorBuilder.matchInport(link.dst().port()); | ||
227 | + selectorBuilder.matchLambda((short) la.toInt()); | ||
228 | + } | ||
229 | + | ||
230 | + // build the last T port rule | ||
231 | + TrafficTreatment treatmentLast = builder() | ||
232 | + .setOutput(intent.dst().port()).build(); | ||
233 | + FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(), | ||
234 | + selectorBuilder.build(), | ||
235 | + treatmentLast, | ||
236 | + 100, | ||
237 | + appId, | ||
238 | + 100, | ||
239 | + true); | ||
240 | + rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule)); | ||
241 | + | ||
242 | + return Lists.newArrayList(new FlowRuleBatchOperation(rules)); | ||
243 | + } | ||
244 | + | ||
245 | +} |
core/net/src/main/java/org/onlab/onos/net/resource/impl/DefaultLinkResourceAllocations.java
0 → 100644
1 | +package org.onlab.onos.net.resource.impl; | ||
2 | + | ||
3 | +import java.util.Collection; | ||
4 | +import java.util.Collections; | ||
5 | +import java.util.Map; | ||
6 | +import java.util.Set; | ||
7 | + | ||
8 | +import org.onlab.onos.net.Link; | ||
9 | +import org.onlab.onos.net.intent.IntentId; | ||
10 | +import org.onlab.onos.net.resource.LinkResourceAllocations; | ||
11 | +import org.onlab.onos.net.resource.LinkResourceRequest; | ||
12 | +import org.onlab.onos.net.resource.ResourceAllocation; | ||
13 | +import org.onlab.onos.net.resource.ResourceRequest; | ||
14 | +import org.onlab.onos.net.resource.ResourceType; | ||
15 | + | ||
16 | +/** | ||
17 | + * Implementation of {@link LinkResourceAllocations}. | ||
18 | + */ | ||
19 | +public class DefaultLinkResourceAllocations implements LinkResourceAllocations { | ||
20 | + private final LinkResourceRequest request; | ||
21 | + private final Map<Link, Set<ResourceAllocation>> allocations; | ||
22 | + | ||
23 | + /** | ||
24 | + * Creates a new link resource allocations. | ||
25 | + * | ||
26 | + * @param request requested resources | ||
27 | + * @param allocations allocated resources | ||
28 | + */ | ||
29 | + protected DefaultLinkResourceAllocations(LinkResourceRequest request, | ||
30 | + Map<Link, Set<ResourceAllocation>> allocations) { | ||
31 | + this.request = request; | ||
32 | + this.allocations = allocations; | ||
33 | + } | ||
34 | + | ||
35 | + @Override | ||
36 | + public IntentId intendId() { | ||
37 | + return request.intendId(); | ||
38 | + } | ||
39 | + | ||
40 | + @Override | ||
41 | + public Collection<Link> links() { | ||
42 | + return request.links(); | ||
43 | + } | ||
44 | + | ||
45 | + @Override | ||
46 | + public Set<ResourceRequest> resources() { | ||
47 | + return request.resources(); | ||
48 | + } | ||
49 | + | ||
50 | + @Override | ||
51 | + public ResourceType type() { | ||
52 | + return null; | ||
53 | + } | ||
54 | + | ||
55 | + @Override | ||
56 | + public Set<ResourceAllocation> getResourceAllocation(Link link) { | ||
57 | + Set<ResourceAllocation> result = allocations.get(link); | ||
58 | + if (result == null) { | ||
59 | + result = Collections.emptySet(); | ||
60 | + } | ||
61 | + return result; | ||
62 | + } | ||
63 | + | ||
64 | +} |
1 | +package org.onlab.onos.net.resource.impl; | ||
2 | + | ||
3 | +import static org.slf4j.LoggerFactory.getLogger; | ||
4 | + | ||
5 | +import java.util.HashMap; | ||
6 | +import java.util.Map; | ||
7 | +import java.util.Set; | ||
8 | + | ||
9 | +import org.apache.felix.scr.annotations.Activate; | ||
10 | +import org.apache.felix.scr.annotations.Component; | ||
11 | +import org.apache.felix.scr.annotations.Deactivate; | ||
12 | +import org.apache.felix.scr.annotations.Service; | ||
13 | +import org.onlab.onos.net.Link; | ||
14 | +import org.onlab.onos.net.intent.IntentId; | ||
15 | +import org.onlab.onos.net.resource.BandwidthResourceAllocation; | ||
16 | +import org.onlab.onos.net.resource.BandwidthResourceRequest; | ||
17 | +import org.onlab.onos.net.resource.Lambda; | ||
18 | +import org.onlab.onos.net.resource.LambdaResourceAllocation; | ||
19 | +import org.onlab.onos.net.resource.LinkResourceAllocations; | ||
20 | +import org.onlab.onos.net.resource.LinkResourceRequest; | ||
21 | +import org.onlab.onos.net.resource.LinkResourceService; | ||
22 | +import org.onlab.onos.net.resource.ResourceAllocation; | ||
23 | +import org.onlab.onos.net.resource.ResourceRequest; | ||
24 | +import org.slf4j.Logger; | ||
25 | + | ||
26 | +import com.google.common.collect.Sets; | ||
27 | + | ||
28 | +/** | ||
29 | + * Provides basic implementation of link resources allocation. | ||
30 | + */ | ||
31 | +@Component(immediate = true) | ||
32 | +@Service | ||
33 | +public class LinkResourceManager implements LinkResourceService { | ||
34 | + | ||
35 | + private final Logger log = getLogger(getClass()); | ||
36 | + | ||
37 | + @Activate | ||
38 | + public void activate() { | ||
39 | + log.info("Started"); | ||
40 | + } | ||
41 | + | ||
42 | + @Deactivate | ||
43 | + public void deactivate() { | ||
44 | + log.info("Stopped"); | ||
45 | + } | ||
46 | + | ||
47 | + @Override | ||
48 | + public LinkResourceAllocations requestResources(LinkResourceRequest req) { | ||
49 | + // TODO implement it using a resource data store. | ||
50 | + | ||
51 | + ResourceAllocation alloc = null; | ||
52 | + for (ResourceRequest r: req.resources()) { | ||
53 | + switch (r.type()) { | ||
54 | + case BANDWIDTH: | ||
55 | + log.info("requestResources() always returns requested bandwidth"); | ||
56 | + BandwidthResourceRequest br = (BandwidthResourceRequest) r; | ||
57 | + alloc = new BandwidthResourceAllocation(br.bandwidth()); | ||
58 | + break; | ||
59 | + case LAMBDA: | ||
60 | + log.info("requestResources() always returns lambda 7"); | ||
61 | + alloc = new LambdaResourceAllocation(Lambda.valueOf(7)); | ||
62 | + break; | ||
63 | + default: | ||
64 | + break; | ||
65 | + } | ||
66 | + } | ||
67 | + | ||
68 | + Map<Link, Set<ResourceAllocation>> allocations = new HashMap<>(); | ||
69 | + for (Link link: req.links()) { | ||
70 | + allocations.put(link, Sets.newHashSet(alloc)); | ||
71 | + } | ||
72 | + return new DefaultLinkResourceAllocations(req, allocations); | ||
73 | + } | ||
74 | + | ||
75 | + @Override | ||
76 | + public void releaseResources(LinkResourceAllocations allocations) { | ||
77 | + // TODO Auto-generated method stub | ||
78 | + | ||
79 | + } | ||
80 | + | ||
81 | + @Override | ||
82 | + public Iterable<LinkResourceAllocations> getAllocations() { | ||
83 | + // TODO Auto-generated method stub | ||
84 | + return null; | ||
85 | + } | ||
86 | + | ||
87 | + @Override | ||
88 | + public LinkResourceAllocations getAllocations(IntentId intentId) { | ||
89 | + // TODO Auto-generated method stub | ||
90 | + return null; | ||
91 | + } | ||
92 | + | ||
93 | + @Override | ||
94 | + public Iterable<LinkResourceAllocations> getAllocations(Link link) { | ||
95 | + // TODO Auto-generated method stub | ||
96 | + return null; | ||
97 | + } | ||
98 | + | ||
99 | + @Override | ||
100 | + public Iterable<IntentId> getIntents(Link link) { | ||
101 | + // TODO Auto-generated method stub | ||
102 | + return null; | ||
103 | + } | ||
104 | + | ||
105 | + @Override | ||
106 | + public ResourceRequest getAvailableResources(Link link) { | ||
107 | + // TODO Auto-generated method stub | ||
108 | + return null; | ||
109 | + } | ||
110 | + | ||
111 | +} |
... | @@ -157,16 +157,12 @@ public class StatisticManager implements StatisticService { | ... | @@ -157,16 +157,12 @@ public class StatisticManager implements StatisticService { |
157 | case RULE_UPDATED: | 157 | case RULE_UPDATED: |
158 | if (rule instanceof FlowEntry) { | 158 | if (rule instanceof FlowEntry) { |
159 | statisticStore.addOrUpdateStatistic((FlowEntry) rule); | 159 | statisticStore.addOrUpdateStatistic((FlowEntry) rule); |
160 | - } else { | ||
161 | - log.warn("IT AIN'T A FLOWENTRY"); | ||
162 | } | 160 | } |
163 | break; | 161 | break; |
164 | case RULE_ADD_REQUESTED: | 162 | case RULE_ADD_REQUESTED: |
165 | - log.info("Preparing for stats"); | ||
166 | statisticStore.prepareForStatistics(rule); | 163 | statisticStore.prepareForStatistics(rule); |
167 | break; | 164 | break; |
168 | case RULE_REMOVE_REQUESTED: | 165 | case RULE_REMOVE_REQUESTED: |
169 | - log.info("Removing stats"); | ||
170 | statisticStore.removeFromStatistics(rule); | 166 | statisticStore.removeFromStatistics(rule); |
171 | break; | 167 | break; |
172 | case RULE_REMOVED: | 168 | case RULE_REMOVED: | ... | ... |
1 | package org.onlab.onos.net.flow.impl; | 1 | package org.onlab.onos.net.flow.impl; |
2 | 2 | ||
3 | - | 3 | +import static org.junit.Assert.assertEquals; |
4 | - | 4 | +import static org.junit.Assert.assertFalse; |
5 | -import static org.onlab.onos.net.flow.FlowRuleEvent.Type.*; | 5 | +import static org.junit.Assert.assertNotNull; |
6 | - | 6 | +import static org.junit.Assert.assertTrue; |
7 | +import static org.junit.Assert.fail; | ||
8 | +import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED; | ||
9 | +import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADD_REQUESTED; | ||
10 | +import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | ||
11 | +import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVE_REQUESTED; | ||
12 | +import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED; | ||
7 | 13 | ||
8 | import java.util.ArrayList; | 14 | import java.util.ArrayList; |
9 | import java.util.Collections; | 15 | import java.util.Collections; |
... | @@ -12,6 +18,7 @@ import java.util.List; | ... | @@ -12,6 +18,7 @@ import java.util.List; |
12 | import java.util.Map; | 18 | import java.util.Map; |
13 | import java.util.Set; | 19 | import java.util.Set; |
14 | import java.util.concurrent.ExecutionException; | 20 | import java.util.concurrent.ExecutionException; |
21 | +import java.util.concurrent.Executor; | ||
15 | import java.util.concurrent.Future; | 22 | import java.util.concurrent.Future; |
16 | import java.util.concurrent.TimeUnit; | 23 | import java.util.concurrent.TimeUnit; |
17 | import java.util.concurrent.TimeoutException; | 24 | import java.util.concurrent.TimeoutException; |
... | @@ -31,6 +38,7 @@ import org.onlab.onos.net.Port; | ... | @@ -31,6 +38,7 @@ import org.onlab.onos.net.Port; |
31 | import org.onlab.onos.net.PortNumber; | 38 | import org.onlab.onos.net.PortNumber; |
32 | import org.onlab.onos.net.device.DeviceListener; | 39 | import org.onlab.onos.net.device.DeviceListener; |
33 | import org.onlab.onos.net.device.DeviceService; | 40 | import org.onlab.onos.net.device.DeviceService; |
41 | +import org.onlab.onos.net.flow.BatchOperation; | ||
34 | import org.onlab.onos.net.flow.CompletedBatchOperation; | 42 | import org.onlab.onos.net.flow.CompletedBatchOperation; |
35 | import org.onlab.onos.net.flow.DefaultFlowEntry; | 43 | import org.onlab.onos.net.flow.DefaultFlowEntry; |
36 | import org.onlab.onos.net.flow.DefaultFlowRule; | 44 | import org.onlab.onos.net.flow.DefaultFlowRule; |
... | @@ -50,7 +58,6 @@ import org.onlab.onos.net.flow.TrafficSelector; | ... | @@ -50,7 +58,6 @@ import org.onlab.onos.net.flow.TrafficSelector; |
50 | import org.onlab.onos.net.flow.TrafficTreatment; | 58 | import org.onlab.onos.net.flow.TrafficTreatment; |
51 | import org.onlab.onos.net.flow.criteria.Criterion; | 59 | import org.onlab.onos.net.flow.criteria.Criterion; |
52 | import org.onlab.onos.net.flow.instructions.Instruction; | 60 | import org.onlab.onos.net.flow.instructions.Instruction; |
53 | -import org.onlab.onos.net.flow.BatchOperation; | ||
54 | import org.onlab.onos.net.provider.AbstractProvider; | 61 | import org.onlab.onos.net.provider.AbstractProvider; |
55 | import org.onlab.onos.net.provider.ProviderId; | 62 | import org.onlab.onos.net.provider.ProviderId; |
56 | import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore; | 63 | import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore; |
... | @@ -59,16 +66,7 @@ import com.google.common.collect.ImmutableList; | ... | @@ -59,16 +66,7 @@ import com.google.common.collect.ImmutableList; |
59 | import com.google.common.collect.ImmutableMap; | 66 | import com.google.common.collect.ImmutableMap; |
60 | import com.google.common.collect.Lists; | 67 | import com.google.common.collect.Lists; |
61 | import com.google.common.collect.Sets; | 68 | import com.google.common.collect.Sets; |
62 | - | 69 | +import com.google.common.util.concurrent.ListenableFuture; |
63 | -import static java.util.Collections.EMPTY_LIST; | ||
64 | -import static org.junit.Assert.assertEquals; | ||
65 | -import static org.junit.Assert.assertFalse; | ||
66 | -import static org.junit.Assert.assertNotNull; | ||
67 | -import static org.junit.Assert.assertTrue; | ||
68 | -import static org.junit.Assert.fail; | ||
69 | -import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED; | ||
70 | -import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | ||
71 | -import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED; | ||
72 | 70 | ||
73 | /** | 71 | /** |
74 | * Test codifying the flow rule service & flow rule provider service contracts. | 72 | * Test codifying the flow rule service & flow rule provider service contracts. |
... | @@ -182,7 +180,6 @@ public class FlowRuleManagerTest { | ... | @@ -182,7 +180,6 @@ public class FlowRuleManagerTest { |
182 | 180 | ||
183 | // TODO: If preserving iteration order is a requirement, redo FlowRuleStore. | 181 | // TODO: If preserving iteration order is a requirement, redo FlowRuleStore. |
184 | //backing store is sensitive to the order of additions/removals | 182 | //backing store is sensitive to the order of additions/removals |
185 | - @SuppressWarnings("unchecked") | ||
186 | private boolean validateState(Map<FlowRule, FlowEntryState> expected) { | 183 | private boolean validateState(Map<FlowRule, FlowEntryState> expected) { |
187 | Map<FlowRule, FlowEntryState> expectedToCheck = new HashMap<>(expected); | 184 | Map<FlowRule, FlowEntryState> expectedToCheck = new HashMap<>(expected); |
188 | Iterable<FlowEntry> rules = service.getFlowEntries(DID); | 185 | Iterable<FlowEntry> rules = service.getFlowEntries(DID); |
... | @@ -526,13 +523,13 @@ public class FlowRuleManagerTest { | ... | @@ -526,13 +523,13 @@ public class FlowRuleManagerTest { |
526 | } | 523 | } |
527 | 524 | ||
528 | @Override | 525 | @Override |
529 | - public Future<CompletedBatchOperation> executeBatch( | 526 | + public ListenableFuture<CompletedBatchOperation> executeBatch( |
530 | BatchOperation<FlowRuleBatchEntry> batch) { | 527 | BatchOperation<FlowRuleBatchEntry> batch) { |
531 | return new TestInstallationFuture(); | 528 | return new TestInstallationFuture(); |
532 | } | 529 | } |
533 | 530 | ||
534 | private class TestInstallationFuture | 531 | private class TestInstallationFuture |
535 | - implements Future<CompletedBatchOperation> { | 532 | + implements ListenableFuture<CompletedBatchOperation> { |
536 | 533 | ||
537 | @Override | 534 | @Override |
538 | public boolean cancel(boolean mayInterruptIfRunning) { | 535 | public boolean cancel(boolean mayInterruptIfRunning) { |
... | @@ -550,10 +547,9 @@ public class FlowRuleManagerTest { | ... | @@ -550,10 +547,9 @@ public class FlowRuleManagerTest { |
550 | } | 547 | } |
551 | 548 | ||
552 | @Override | 549 | @Override |
553 | - @SuppressWarnings("unchecked") | ||
554 | public CompletedBatchOperation get() | 550 | public CompletedBatchOperation get() |
555 | throws InterruptedException, ExecutionException { | 551 | throws InterruptedException, ExecutionException { |
556 | - return new CompletedBatchOperation(true, EMPTY_LIST); | 552 | + return new CompletedBatchOperation(true, Collections.<FlowEntry>emptySet()); |
557 | } | 553 | } |
558 | 554 | ||
559 | @Override | 555 | @Override |
... | @@ -562,6 +558,11 @@ public class FlowRuleManagerTest { | ... | @@ -562,6 +558,11 @@ public class FlowRuleManagerTest { |
562 | ExecutionException, TimeoutException { | 558 | ExecutionException, TimeoutException { |
563 | return null; | 559 | return null; |
564 | } | 560 | } |
561 | + | ||
562 | + @Override | ||
563 | + public void addListener(Runnable task, Executor executor) { | ||
564 | + // TODO: add stuff. | ||
565 | + } | ||
565 | } | 566 | } |
566 | 567 | ||
567 | } | 568 | } |
... | @@ -581,6 +582,12 @@ public class FlowRuleManagerTest { | ... | @@ -581,6 +582,12 @@ public class FlowRuleManagerTest { |
581 | } | 582 | } |
582 | 583 | ||
583 | @Override | 584 | @Override |
585 | + public Criterion getCriterion( | ||
586 | + org.onlab.onos.net.flow.criteria.Criterion.Type type) { | ||
587 | + return null; | ||
588 | + } | ||
589 | + | ||
590 | + @Override | ||
584 | public int hashCode() { | 591 | public int hashCode() { |
585 | return testval; | 592 | return testval; |
586 | } | 593 | } |
... | @@ -592,6 +599,7 @@ public class FlowRuleManagerTest { | ... | @@ -592,6 +599,7 @@ public class FlowRuleManagerTest { |
592 | } | 599 | } |
593 | return false; | 600 | return false; |
594 | } | 601 | } |
602 | + | ||
595 | } | 603 | } |
596 | 604 | ||
597 | private class TestTreatment implements TrafficTreatment { | 605 | private class TestTreatment implements TrafficTreatment { | ... | ... |
1 | package org.onlab.onos.net.intent; | 1 | package org.onlab.onos.net.intent; |
2 | 2 | ||
3 | +import static org.onlab.onos.net.NetTestTools.createPath; | ||
4 | + | ||
3 | import java.util.ArrayList; | 5 | import java.util.ArrayList; |
4 | import java.util.Arrays; | 6 | import java.util.Arrays; |
5 | import java.util.Collections; | 7 | import java.util.Collections; |
... | @@ -12,12 +14,11 @@ import org.onlab.onos.net.Path; | ... | @@ -12,12 +14,11 @@ import org.onlab.onos.net.Path; |
12 | import org.onlab.onos.net.flow.TrafficSelector; | 14 | import org.onlab.onos.net.flow.TrafficSelector; |
13 | import org.onlab.onos.net.flow.TrafficTreatment; | 15 | import org.onlab.onos.net.flow.TrafficTreatment; |
14 | import org.onlab.onos.net.flow.criteria.Criterion; | 16 | import org.onlab.onos.net.flow.criteria.Criterion; |
17 | +import org.onlab.onos.net.flow.criteria.Criterion.Type; | ||
15 | import org.onlab.onos.net.flow.instructions.Instruction; | 18 | import org.onlab.onos.net.flow.instructions.Instruction; |
16 | import org.onlab.onos.net.topology.LinkWeight; | 19 | import org.onlab.onos.net.topology.LinkWeight; |
17 | import org.onlab.onos.net.topology.PathService; | 20 | import org.onlab.onos.net.topology.PathService; |
18 | 21 | ||
19 | -import static org.onlab.onos.net.NetTestTools.createPath; | ||
20 | - | ||
21 | /** | 22 | /** |
22 | * Common mocks used by the intent framework tests. | 23 | * Common mocks used by the intent framework tests. |
23 | */ | 24 | */ |
... | @@ -30,6 +31,11 @@ public class IntentTestsMocks { | ... | @@ -30,6 +31,11 @@ public class IntentTestsMocks { |
30 | public Set<Criterion> criteria() { | 31 | public Set<Criterion> criteria() { |
31 | return new HashSet<>(); | 32 | return new HashSet<>(); |
32 | } | 33 | } |
34 | + | ||
35 | + @Override | ||
36 | + public Criterion getCriterion(Type type) { | ||
37 | + return null; | ||
38 | + } | ||
33 | } | 39 | } |
34 | 40 | ||
35 | /** | 41 | /** | ... | ... |
... | @@ -103,7 +103,7 @@ public class ClusterCommunicationManager | ... | @@ -103,7 +103,7 @@ public class ClusterCommunicationManager |
103 | final ControllerNode localNode = clusterService.getLocalNode(); | 103 | final ControllerNode localNode = clusterService.getLocalNode(); |
104 | for (NodeId nodeId : nodes) { | 104 | for (NodeId nodeId : nodes) { |
105 | if (!nodeId.equals(localNode.id())) { | 105 | if (!nodeId.equals(localNode.id())) { |
106 | - ok = unicast(message, nodeId) && ok; | 106 | + ok = unicastUnchecked(message, nodeId) && ok; |
107 | } | 107 | } |
108 | } | 108 | } |
109 | return ok; | 109 | return ok; |
... | @@ -124,6 +124,14 @@ public class ClusterCommunicationManager | ... | @@ -124,6 +124,14 @@ public class ClusterCommunicationManager |
124 | } | 124 | } |
125 | } | 125 | } |
126 | 126 | ||
127 | + private boolean unicastUnchecked(ClusterMessage message, NodeId toNodeId) throws IOException { | ||
128 | + try { | ||
129 | + return unicast(message, toNodeId); | ||
130 | + } catch (IOException e) { | ||
131 | + return false; | ||
132 | + } | ||
133 | + } | ||
134 | + | ||
127 | @Override | 135 | @Override |
128 | public ClusterMessageResponse sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException { | 136 | public ClusterMessageResponse sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException { |
129 | ControllerNode node = clusterService.getNode(toNodeId); | 137 | ControllerNode node = clusterService.getNode(toNodeId); | ... | ... |
... | @@ -3,12 +3,21 @@ package org.onlab.onos.store.flow.impl; | ... | @@ -3,12 +3,21 @@ package org.onlab.onos.store.flow.impl; |
3 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | 3 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; |
4 | import static org.slf4j.LoggerFactory.getLogger; | 4 | import static org.slf4j.LoggerFactory.getLogger; |
5 | import static org.onlab.onos.store.flow.impl.FlowStoreMessageSubjects.*; | 5 | import static org.onlab.onos.store.flow.impl.FlowStoreMessageSubjects.*; |
6 | +import static org.onlab.util.Tools.namedThreads; | ||
6 | 7 | ||
7 | import java.io.IOException; | 8 | import java.io.IOException; |
9 | +import java.util.ArrayList; | ||
10 | +import java.util.Arrays; | ||
8 | import java.util.Collection; | 11 | import java.util.Collection; |
9 | import java.util.Collections; | 12 | import java.util.Collections; |
13 | +import java.util.Map; | ||
14 | +import java.util.concurrent.ExecutorService; | ||
15 | +import java.util.concurrent.Executors; | ||
16 | +import java.util.concurrent.Future; | ||
10 | import java.util.concurrent.TimeUnit; | 17 | import java.util.concurrent.TimeUnit; |
11 | import java.util.concurrent.TimeoutException; | 18 | import java.util.concurrent.TimeoutException; |
19 | +import java.util.concurrent.atomic.AtomicInteger; | ||
20 | +import java.util.List; | ||
12 | 21 | ||
13 | import org.apache.felix.scr.annotations.Activate; | 22 | import org.apache.felix.scr.annotations.Activate; |
14 | import org.apache.felix.scr.annotations.Component; | 23 | import org.apache.felix.scr.annotations.Component; |
... | @@ -18,12 +27,20 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; | ... | @@ -18,12 +27,20 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; |
18 | import org.apache.felix.scr.annotations.Service; | 27 | import org.apache.felix.scr.annotations.Service; |
19 | import org.onlab.onos.ApplicationId; | 28 | import org.onlab.onos.ApplicationId; |
20 | import org.onlab.onos.cluster.ClusterService; | 29 | import org.onlab.onos.cluster.ClusterService; |
30 | +import org.onlab.onos.net.Device; | ||
21 | import org.onlab.onos.net.DeviceId; | 31 | import org.onlab.onos.net.DeviceId; |
32 | +import org.onlab.onos.net.device.DeviceService; | ||
33 | +import org.onlab.onos.net.flow.CompletedBatchOperation; | ||
22 | import org.onlab.onos.net.flow.DefaultFlowEntry; | 34 | import org.onlab.onos.net.flow.DefaultFlowEntry; |
23 | import org.onlab.onos.net.flow.FlowEntry; | 35 | import org.onlab.onos.net.flow.FlowEntry; |
24 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; | 36 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; |
25 | import org.onlab.onos.net.flow.FlowRule; | 37 | import org.onlab.onos.net.flow.FlowRule; |
38 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry; | ||
39 | +import org.onlab.onos.net.flow.FlowRuleBatchEvent; | ||
40 | +import org.onlab.onos.net.flow.FlowRuleBatchOperation; | ||
41 | +import org.onlab.onos.net.flow.FlowRuleBatchRequest; | ||
26 | import org.onlab.onos.net.flow.FlowRuleEvent; | 42 | import org.onlab.onos.net.flow.FlowRuleEvent; |
43 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | ||
27 | import org.onlab.onos.net.flow.FlowRuleEvent.Type; | 44 | import org.onlab.onos.net.flow.FlowRuleEvent.Type; |
28 | import org.onlab.onos.net.flow.FlowRuleStore; | 45 | import org.onlab.onos.net.flow.FlowRuleStore; |
29 | import org.onlab.onos.net.flow.FlowRuleStoreDelegate; | 46 | import org.onlab.onos.net.flow.FlowRuleStoreDelegate; |
... | @@ -42,7 +59,12 @@ import org.slf4j.Logger; | ... | @@ -42,7 +59,12 @@ import org.slf4j.Logger; |
42 | 59 | ||
43 | import com.google.common.collect.ArrayListMultimap; | 60 | import com.google.common.collect.ArrayListMultimap; |
44 | import com.google.common.collect.ImmutableSet; | 61 | import com.google.common.collect.ImmutableSet; |
62 | +import com.google.common.collect.Iterables; | ||
63 | +import com.google.common.collect.Maps; | ||
45 | import com.google.common.collect.Multimap; | 64 | import com.google.common.collect.Multimap; |
65 | +import com.google.common.util.concurrent.Futures; | ||
66 | +import com.google.common.util.concurrent.ListenableFuture; | ||
67 | +import com.google.common.util.concurrent.SettableFuture; | ||
46 | 68 | ||
47 | /** | 69 | /** |
48 | * Manages inventory of flow rules using a distributed state management protocol. | 70 | * Manages inventory of flow rules using a distributed state management protocol. |
... | @@ -50,7 +72,7 @@ import com.google.common.collect.Multimap; | ... | @@ -50,7 +72,7 @@ import com.google.common.collect.Multimap; |
50 | @Component(immediate = true) | 72 | @Component(immediate = true) |
51 | @Service | 73 | @Service |
52 | public class DistributedFlowRuleStore | 74 | public class DistributedFlowRuleStore |
53 | - extends AbstractStore<FlowRuleEvent, FlowRuleStoreDelegate> | 75 | + extends AbstractStore<FlowRuleBatchEvent, FlowRuleStoreDelegate> |
54 | implements FlowRuleStore { | 76 | implements FlowRuleStore { |
55 | 77 | ||
56 | private final Logger log = getLogger(getClass()); | 78 | private final Logger log = getLogger(getClass()); |
... | @@ -63,13 +85,26 @@ public class DistributedFlowRuleStore | ... | @@ -63,13 +85,26 @@ public class DistributedFlowRuleStore |
63 | ArrayListMultimap.<Short, FlowRule>create(); | 85 | ArrayListMultimap.<Short, FlowRule>create(); |
64 | 86 | ||
65 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 87 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
66 | - private ReplicaInfoService replicaInfoManager; | 88 | + protected ReplicaInfoService replicaInfoManager; |
67 | 89 | ||
68 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 90 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
69 | - private ClusterCommunicationService clusterCommunicator; | 91 | + protected ClusterCommunicationService clusterCommunicator; |
70 | 92 | ||
71 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 93 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
72 | - private ClusterService clusterService; | 94 | + protected ClusterService clusterService; |
95 | + | ||
96 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
97 | + protected DeviceService deviceService; | ||
98 | + | ||
99 | + private final AtomicInteger localBatchIdGen = new AtomicInteger(); | ||
100 | + | ||
101 | + | ||
102 | + // FIXME switch to expiraing map/Cache? | ||
103 | + private Map<Integer, SettableFuture<CompletedBatchOperation>> pendingFutures = Maps.newConcurrentMap(); | ||
104 | + | ||
105 | + private final ExecutorService futureListeners = | ||
106 | + Executors.newCachedThreadPool(namedThreads("flowstore-peer-responders")); | ||
107 | + | ||
73 | 108 | ||
74 | protected static final KryoSerializer SERIALIZER = new KryoSerializer() { | 109 | protected static final KryoSerializer SERIALIZER = new KryoSerializer() { |
75 | @Override | 110 | @Override |
... | @@ -86,38 +121,44 @@ public class DistributedFlowRuleStore | ... | @@ -86,38 +121,44 @@ public class DistributedFlowRuleStore |
86 | 121 | ||
87 | @Activate | 122 | @Activate |
88 | public void activate() { | 123 | public void activate() { |
89 | - clusterCommunicator.addSubscriber(STORE_FLOW_RULE, new ClusterMessageHandler() { | 124 | + clusterCommunicator.addSubscriber(APPLY_BATCH_FLOWS, new ClusterMessageHandler() { |
90 | 125 | ||
91 | @Override | 126 | @Override |
92 | - public void handle(ClusterMessage message) { | 127 | + public void handle(final ClusterMessage message) { |
93 | - FlowRule rule = SERIALIZER.decode(message.payload()); | 128 | + FlowRuleBatchOperation operation = SERIALIZER.decode(message.payload()); |
94 | - log.info("received add request for {}", rule); | 129 | + log.info("received batch request {}", operation); |
95 | - storeFlowEntryInternal(rule); | 130 | + final ListenableFuture<CompletedBatchOperation> f = storeBatchInternal(operation); |
96 | - // FIXME what to respond. | 131 | + |
132 | + f.addListener(new Runnable() { | ||
133 | + | ||
134 | + @Override | ||
135 | + public void run() { | ||
136 | + CompletedBatchOperation result = Futures.getUnchecked(f); | ||
97 | try { | 137 | try { |
98 | - message.respond(SERIALIZER.encode("ACK")); | 138 | + message.respond(SERIALIZER.encode(result)); |
99 | } catch (IOException e) { | 139 | } catch (IOException e) { |
100 | log.error("Failed to respond back", e); | 140 | log.error("Failed to respond back", e); |
101 | } | 141 | } |
102 | } | 142 | } |
143 | + }, futureListeners); | ||
144 | + } | ||
103 | }); | 145 | }); |
104 | 146 | ||
105 | - clusterCommunicator.addSubscriber(DELETE_FLOW_RULE, new ClusterMessageHandler() { | 147 | + clusterCommunicator.addSubscriber(GET_FLOW_ENTRY, new ClusterMessageHandler() { |
106 | 148 | ||
107 | @Override | 149 | @Override |
108 | public void handle(ClusterMessage message) { | 150 | public void handle(ClusterMessage message) { |
109 | FlowRule rule = SERIALIZER.decode(message.payload()); | 151 | FlowRule rule = SERIALIZER.decode(message.payload()); |
110 | - log.info("received delete request for {}", rule); | 152 | + log.info("received get flow entry request for {}", rule); |
111 | - deleteFlowRuleInternal(rule); | 153 | + FlowEntry flowEntry = getFlowEntryInternal(rule); |
112 | - // FIXME what to respond. | ||
113 | try { | 154 | try { |
114 | - message.respond(SERIALIZER.encode("ACK")); | 155 | + message.respond(SERIALIZER.encode(flowEntry)); |
115 | } catch (IOException e) { | 156 | } catch (IOException e) { |
116 | log.error("Failed to respond back", e); | 157 | log.error("Failed to respond back", e); |
117 | } | 158 | } |
118 | - | ||
119 | } | 159 | } |
120 | }); | 160 | }); |
161 | + | ||
121 | log.info("Started"); | 162 | log.info("Started"); |
122 | } | 163 | } |
123 | 164 | ||
... | @@ -127,16 +168,44 @@ public class DistributedFlowRuleStore | ... | @@ -127,16 +168,44 @@ public class DistributedFlowRuleStore |
127 | } | 168 | } |
128 | 169 | ||
129 | 170 | ||
171 | + // TODO: This is not a efficient operation on a distributed sharded | ||
172 | + // flow store. We need to revisit the need for this operation or at least | ||
173 | + // make it device specific. | ||
130 | @Override | 174 | @Override |
131 | public int getFlowRuleCount() { | 175 | public int getFlowRuleCount() { |
132 | - return flowEntries.size(); | 176 | + // implementing in-efficient operation for debugging purpose. |
177 | + int sum = 0; | ||
178 | + for (Device device : deviceService.getDevices()) { | ||
179 | + final DeviceId did = device.id(); | ||
180 | + sum += Iterables.size(getFlowEntries(did)); | ||
181 | + } | ||
182 | + return sum; | ||
133 | } | 183 | } |
134 | 184 | ||
135 | @Override | 185 | @Override |
136 | public synchronized FlowEntry getFlowEntry(FlowRule rule) { | 186 | public synchronized FlowEntry getFlowEntry(FlowRule rule) { |
187 | + ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); | ||
188 | + if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { | ||
137 | return getFlowEntryInternal(rule); | 189 | return getFlowEntryInternal(rule); |
138 | } | 190 | } |
139 | 191 | ||
192 | + log.info("Forwarding getFlowEntry to {}, which is the primary (master) for device {}", | ||
193 | + replicaInfo.master().orNull(), rule.deviceId()); | ||
194 | + | ||
195 | + ClusterMessage message = new ClusterMessage( | ||
196 | + clusterService.getLocalNode().id(), | ||
197 | + FlowStoreMessageSubjects.GET_FLOW_ENTRY, | ||
198 | + SERIALIZER.encode(rule)); | ||
199 | + | ||
200 | + try { | ||
201 | + ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); | ||
202 | + return SERIALIZER.decode(response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); | ||
203 | + } catch (IOException | TimeoutException e) { | ||
204 | + // FIXME: throw a FlowStoreException | ||
205 | + throw new RuntimeException(e); | ||
206 | + } | ||
207 | + } | ||
208 | + | ||
140 | private synchronized StoredFlowEntry getFlowEntryInternal(FlowRule rule) { | 209 | private synchronized StoredFlowEntry getFlowEntryInternal(FlowRule rule) { |
141 | for (StoredFlowEntry f : flowEntries.get(rule.deviceId())) { | 210 | for (StoredFlowEntry f : flowEntries.get(rule.deviceId())) { |
142 | if (f.equals(rule)) { | 211 | if (f.equals(rule)) { |
... | @@ -165,19 +234,31 @@ public class DistributedFlowRuleStore | ... | @@ -165,19 +234,31 @@ public class DistributedFlowRuleStore |
165 | } | 234 | } |
166 | 235 | ||
167 | @Override | 236 | @Override |
168 | - public boolean storeFlowRule(FlowRule rule) { | 237 | + public void storeFlowRule(FlowRule rule) { |
169 | - ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); | 238 | + storeBatch(new FlowRuleBatchOperation(Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)))); |
239 | + } | ||
240 | + | ||
241 | + @Override | ||
242 | + public Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation operation) { | ||
243 | + if (operation.getOperations().isEmpty()) { | ||
244 | + return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowEntry>emptySet())); | ||
245 | + } | ||
246 | + | ||
247 | + DeviceId deviceId = operation.getOperations().get(0).getTarget().deviceId(); | ||
248 | + | ||
249 | + ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId); | ||
250 | + | ||
170 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { | 251 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { |
171 | - return storeFlowEntryInternal(rule); | 252 | + return storeBatchInternal(operation); |
172 | } | 253 | } |
173 | 254 | ||
174 | - log.info("Forwarding storeFlowRule to {}, which is the primary (master) for device {}", | 255 | + log.info("Forwarding storeBatch to {}, which is the primary (master) for device {}", |
175 | - replicaInfo.master().orNull(), rule.deviceId()); | 256 | + replicaInfo.master().orNull(), deviceId); |
176 | 257 | ||
177 | ClusterMessage message = new ClusterMessage( | 258 | ClusterMessage message = new ClusterMessage( |
178 | clusterService.getLocalNode().id(), | 259 | clusterService.getLocalNode().id(), |
179 | - FlowStoreMessageSubjects.STORE_FLOW_RULE, | 260 | + APPLY_BATCH_FLOWS, |
180 | - SERIALIZER.encode(rule)); | 261 | + SERIALIZER.encode(operation)); |
181 | 262 | ||
182 | try { | 263 | try { |
183 | ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); | 264 | ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); |
... | @@ -186,58 +267,48 @@ public class DistributedFlowRuleStore | ... | @@ -186,58 +267,48 @@ public class DistributedFlowRuleStore |
186 | // FIXME: throw a FlowStoreException | 267 | // FIXME: throw a FlowStoreException |
187 | throw new RuntimeException(e); | 268 | throw new RuntimeException(e); |
188 | } | 269 | } |
189 | - return false; | 270 | + |
271 | + return null; | ||
190 | } | 272 | } |
191 | 273 | ||
192 | - private synchronized boolean storeFlowEntryInternal(FlowRule flowRule) { | 274 | + private ListenableFuture<CompletedBatchOperation> storeBatchInternal(FlowRuleBatchOperation operation) { |
275 | + List<FlowEntry> toRemove = new ArrayList<>(); | ||
276 | + List<FlowEntry> toAdd = new ArrayList<>(); | ||
277 | + // TODO: backup changes to hazelcast map | ||
278 | + for (FlowRuleBatchEntry batchEntry : operation.getOperations()) { | ||
279 | + FlowRule flowRule = batchEntry.getTarget(); | ||
280 | + FlowRuleOperation op = batchEntry.getOperator(); | ||
281 | + if (op.equals(FlowRuleOperation.REMOVE)) { | ||
282 | + StoredFlowEntry entry = getFlowEntryInternal(flowRule); | ||
283 | + if (entry != null) { | ||
284 | + entry.setState(FlowEntryState.PENDING_REMOVE); | ||
285 | + toRemove.add(entry); | ||
286 | + } | ||
287 | + } else if (op.equals(FlowRuleOperation.ADD)) { | ||
193 | StoredFlowEntry flowEntry = new DefaultFlowEntry(flowRule); | 288 | StoredFlowEntry flowEntry = new DefaultFlowEntry(flowRule); |
194 | DeviceId deviceId = flowRule.deviceId(); | 289 | DeviceId deviceId = flowRule.deviceId(); |
195 | - // write to local copy. | ||
196 | if (!flowEntries.containsEntry(deviceId, flowEntry)) { | 290 | if (!flowEntries.containsEntry(deviceId, flowEntry)) { |
197 | flowEntries.put(deviceId, flowEntry); | 291 | flowEntries.put(deviceId, flowEntry); |
198 | flowEntriesById.put(flowRule.appId(), flowEntry); | 292 | flowEntriesById.put(flowRule.appId(), flowEntry); |
199 | - notifyDelegate(new FlowRuleEvent(Type.RULE_ADD_REQUESTED, flowRule)); | 293 | + toAdd.add(flowEntry); |
200 | - return true; | ||
201 | } | 294 | } |
202 | - // write to backup. | ||
203 | - // TODO: write to a hazelcast map. | ||
204 | - return false; | ||
205 | } | 295 | } |
206 | - | ||
207 | - @Override | ||
208 | - public synchronized boolean deleteFlowRule(FlowRule rule) { | ||
209 | - ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); | ||
210 | - if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { | ||
211 | - return deleteFlowRuleInternal(rule); | ||
212 | } | 296 | } |
213 | - | 297 | + if (toAdd.isEmpty() && toRemove.isEmpty()) { |
214 | - ClusterMessage message = new ClusterMessage( | 298 | + return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowEntry>emptySet())); |
215 | - clusterService.getLocalNode().id(), | ||
216 | - FlowStoreMessageSubjects.DELETE_FLOW_RULE, | ||
217 | - SERIALIZER.encode(rule)); | ||
218 | - | ||
219 | - try { | ||
220 | - ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); | ||
221 | - response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); | ||
222 | - } catch (IOException | TimeoutException e) { | ||
223 | - // FIXME: throw a FlowStoreException | ||
224 | - throw new RuntimeException(e); | ||
225 | } | 299 | } |
226 | - return false; | ||
227 | - } | ||
228 | - | ||
229 | - private synchronized boolean deleteFlowRuleInternal(FlowRule flowRule) { | ||
230 | - StoredFlowEntry entry = getFlowEntryInternal(flowRule); | ||
231 | - if (entry == null) { | ||
232 | - return false; | ||
233 | - } | ||
234 | - entry.setState(FlowEntryState.PENDING_REMOVE); | ||
235 | 300 | ||
236 | - // TODO: also update backup. | 301 | + SettableFuture<CompletedBatchOperation> r = SettableFuture.create(); |
302 | + final int batchId = localBatchIdGen.incrementAndGet(); | ||
237 | 303 | ||
238 | - notifyDelegate(new FlowRuleEvent(Type.RULE_REMOVE_REQUESTED, flowRule)); | 304 | + pendingFutures.put(batchId, r); |
305 | + notifyDelegate(FlowRuleBatchEvent.requested(new FlowRuleBatchRequest(batchId, toAdd, toRemove))); | ||
306 | + return r; | ||
307 | + } | ||
239 | 308 | ||
240 | - return true; | 309 | + @Override |
310 | + public void deleteFlowRule(FlowRule rule) { | ||
311 | + storeBatch(new FlowRuleBatchOperation(Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule)))); | ||
241 | } | 312 | } |
242 | 313 | ||
243 | @Override | 314 | @Override |
... | @@ -247,18 +318,9 @@ public class DistributedFlowRuleStore | ... | @@ -247,18 +318,9 @@ public class DistributedFlowRuleStore |
247 | return addOrUpdateFlowRuleInternal(rule); | 318 | return addOrUpdateFlowRuleInternal(rule); |
248 | } | 319 | } |
249 | 320 | ||
250 | - ClusterMessage message = new ClusterMessage( | 321 | + log.error("Tried to update FlowRule {} state," |
251 | - clusterService.getLocalNode().id(), | 322 | + + " while the Node was not the master.", rule); |
252 | - FlowStoreMessageSubjects.ADD_OR_UPDATE_FLOW_RULE, | 323 | + return null; |
253 | - SERIALIZER.encode(rule)); | ||
254 | - | ||
255 | - try { | ||
256 | - ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); | ||
257 | - return SERIALIZER.decode(response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); | ||
258 | - } catch (IOException | TimeoutException e) { | ||
259 | - // FIXME: throw a FlowStoreException | ||
260 | - throw new RuntimeException(e); | ||
261 | - } | ||
262 | } | 324 | } |
263 | 325 | ||
264 | private synchronized FlowRuleEvent addOrUpdateFlowRuleInternal(FlowEntry rule) { | 326 | private synchronized FlowRuleEvent addOrUpdateFlowRuleInternal(FlowEntry rule) { |
... | @@ -292,18 +354,9 @@ public class DistributedFlowRuleStore | ... | @@ -292,18 +354,9 @@ public class DistributedFlowRuleStore |
292 | return removeFlowRuleInternal(rule); | 354 | return removeFlowRuleInternal(rule); |
293 | } | 355 | } |
294 | 356 | ||
295 | - ClusterMessage message = new ClusterMessage( | 357 | + log.error("Tried to remove FlowRule {}," |
296 | - clusterService.getLocalNode().id(), | 358 | + + " while the Node was not the master.", rule); |
297 | - FlowStoreMessageSubjects.REMOVE_FLOW_RULE, | 359 | + return null; |
298 | - SERIALIZER.encode(rule)); | ||
299 | - | ||
300 | - try { | ||
301 | - ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); | ||
302 | - return SERIALIZER.decode(response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); | ||
303 | - } catch (IOException | TimeoutException e) { | ||
304 | - // FIXME: throw a FlowStoreException | ||
305 | - throw new RuntimeException(e); | ||
306 | - } | ||
307 | } | 360 | } |
308 | 361 | ||
309 | private synchronized FlowRuleEvent removeFlowRuleInternal(FlowEntry rule) { | 362 | private synchronized FlowRuleEvent removeFlowRuleInternal(FlowEntry rule) { |
... | @@ -315,4 +368,14 @@ public class DistributedFlowRuleStore | ... | @@ -315,4 +368,14 @@ public class DistributedFlowRuleStore |
315 | } | 368 | } |
316 | // TODO: also update backup. | 369 | // TODO: also update backup. |
317 | } | 370 | } |
371 | + | ||
372 | + @Override | ||
373 | + public void batchOperationComplete(FlowRuleBatchEvent event) { | ||
374 | + SettableFuture<CompletedBatchOperation> future | ||
375 | + = pendingFutures.get(event.subject().batchId()); | ||
376 | + if (future != null) { | ||
377 | + future.set(event.result()); | ||
378 | + } | ||
379 | + notifyDelegate(event); | ||
380 | + } | ||
318 | } | 381 | } | ... | ... |
... | @@ -7,9 +7,10 @@ import org.onlab.onos.store.cluster.messaging.MessageSubject; | ... | @@ -7,9 +7,10 @@ import org.onlab.onos.store.cluster.messaging.MessageSubject; |
7 | */ | 7 | */ |
8 | public final class FlowStoreMessageSubjects { | 8 | public final class FlowStoreMessageSubjects { |
9 | private FlowStoreMessageSubjects() {} | 9 | private FlowStoreMessageSubjects() {} |
10 | - public static final MessageSubject STORE_FLOW_RULE = new MessageSubject("peer-forward-store-flow-rule"); | 10 | + |
11 | - public static final MessageSubject DELETE_FLOW_RULE = new MessageSubject("peer-forward-delete-flow-rule"); | 11 | + public static final MessageSubject APPLY_BATCH_FLOWS |
12 | - public static final MessageSubject ADD_OR_UPDATE_FLOW_RULE = | 12 | + = new MessageSubject("peer-forward-apply-batch"); |
13 | - new MessageSubject("peer-forward-add-or-update-flow-rule"); | 13 | + |
14 | - public static final MessageSubject REMOVE_FLOW_RULE = new MessageSubject("peer-forward-remove-flow-rule"); | 14 | + public static final MessageSubject GET_FLOW_ENTRY |
15 | + = new MessageSubject("peer-forward-get-flow-entry"); | ||
15 | } | 16 | } | ... | ... |
... | @@ -399,7 +399,7 @@ public class GossipHostStore | ... | @@ -399,7 +399,7 @@ public class GossipHostStore |
399 | } | 399 | } |
400 | 400 | ||
401 | // Auxiliary extension to allow location to mutate. | 401 | // Auxiliary extension to allow location to mutate. |
402 | - private class StoredHost extends DefaultHost { | 402 | + private static final class StoredHost extends DefaultHost { |
403 | private Timestamped<HostLocation> location; | 403 | private Timestamped<HostLocation> location; |
404 | 404 | ||
405 | /** | 405 | /** | ... | ... |
... | @@ -58,7 +58,6 @@ implements MastershipStore { | ... | @@ -58,7 +58,6 @@ implements MastershipStore { |
58 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 58 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
59 | protected ClusterService clusterService; | 59 | protected ClusterService clusterService; |
60 | 60 | ||
61 | - @SuppressWarnings({ "unchecked", "rawtypes" }) | ||
62 | @Override | 61 | @Override |
63 | @Activate | 62 | @Activate |
64 | public void activate() { | 63 | public void activate() { |
... | @@ -76,9 +75,9 @@ implements MastershipStore { | ... | @@ -76,9 +75,9 @@ implements MastershipStore { |
76 | } | 75 | } |
77 | }; | 76 | }; |
78 | 77 | ||
79 | - roleMap = new SMap(theInstance.getMap("nodeRoles"), this.serializer); | 78 | + roleMap = new SMap<>(theInstance.<byte[], byte[]>getMap("nodeRoles"), this.serializer); |
80 | roleMap.addEntryListener((new RemoteMasterShipEventHandler()), true); | 79 | roleMap.addEntryListener((new RemoteMasterShipEventHandler()), true); |
81 | - terms = new SMap(theInstance.getMap("terms"), this.serializer); | 80 | + terms = new SMap<>(theInstance.<byte[], byte[]>getMap("terms"), this.serializer); |
82 | clusterSize = theInstance.getAtomicLong("clustersize"); | 81 | clusterSize = theInstance.getAtomicLong("clustersize"); |
83 | 82 | ||
84 | log.info("Started"); | 83 | log.info("Started"); | ... | ... |
1 | package org.onlab.onos.store.mastership.impl; | 1 | package org.onlab.onos.store.mastership.impl; |
2 | 2 | ||
3 | import java.util.Collections; | 3 | import java.util.Collections; |
4 | -import java.util.HashMap; | 4 | +import java.util.EnumMap; |
5 | import java.util.LinkedList; | 5 | import java.util.LinkedList; |
6 | import java.util.List; | 6 | import java.util.List; |
7 | import java.util.Map; | 7 | import java.util.Map; |
... | @@ -17,9 +17,9 @@ import com.google.common.base.MoreObjects.ToStringHelper; | ... | @@ -17,9 +17,9 @@ import com.google.common.base.MoreObjects.ToStringHelper; |
17 | * A structure that holds node mastership roles associated with a | 17 | * A structure that holds node mastership roles associated with a |
18 | * {@link DeviceId}. This structure needs to be locked through IMap. | 18 | * {@link DeviceId}. This structure needs to be locked through IMap. |
19 | */ | 19 | */ |
20 | -public class RoleValue { | 20 | +final class RoleValue { |
21 | 21 | ||
22 | - protected Map<MastershipRole, List<NodeId>> value = new HashMap<>(); | 22 | + protected final Map<MastershipRole, List<NodeId>> value = new EnumMap<>(MastershipRole.class); |
23 | 23 | ||
24 | public RoleValue() { | 24 | public RoleValue() { |
25 | value.put(MastershipRole.MASTER, new LinkedList<NodeId>()); | 25 | value.put(MastershipRole.MASTER, new LinkedList<NodeId>()); |
... | @@ -27,7 +27,8 @@ public class RoleValue { | ... | @@ -27,7 +27,8 @@ public class RoleValue { |
27 | value.put(MastershipRole.NONE, new LinkedList<NodeId>()); | 27 | value.put(MastershipRole.NONE, new LinkedList<NodeId>()); |
28 | } | 28 | } |
29 | 29 | ||
30 | - public Map<MastershipRole, List<NodeId>> value() { | 30 | + // exposing internals for serialization purpose only |
31 | + Map<MastershipRole, List<NodeId>> value() { | ||
31 | return Collections.unmodifiableMap(value); | 32 | return Collections.unmodifiableMap(value); |
32 | } | 33 | } |
33 | 34 | ... | ... |
... | @@ -35,10 +35,10 @@ public class RoleValueSerializer extends Serializer<RoleValue> { | ... | @@ -35,10 +35,10 @@ public class RoleValueSerializer extends Serializer<RoleValue> { |
35 | 35 | ||
36 | @Override | 36 | @Override |
37 | public void write(Kryo kryo, Output output, RoleValue type) { | 37 | public void write(Kryo kryo, Output output, RoleValue type) { |
38 | - output.writeInt(type.value().size()); | 38 | + final Map<MastershipRole, List<NodeId>> map = type.value(); |
39 | + output.writeInt(map.size()); | ||
39 | 40 | ||
40 | - for (Map.Entry<MastershipRole, List<NodeId>> el : | 41 | + for (Map.Entry<MastershipRole, List<NodeId>> el : map.entrySet()) { |
41 | - type.value().entrySet()) { | ||
42 | output.writeInt(el.getKey().ordinal()); | 42 | output.writeInt(el.getKey().ordinal()); |
43 | 43 | ||
44 | List<NodeId> nodes = el.getValue(); | 44 | List<NodeId> nodes = el.getValue(); | ... | ... |
... | @@ -492,7 +492,10 @@ public class SMap<K, V> implements IMap<K, V> { | ... | @@ -492,7 +492,10 @@ public class SMap<K, V> implements IMap<K, V> { |
492 | } | 492 | } |
493 | 493 | ||
494 | private V deserializeVal(byte[] val) { | 494 | private V deserializeVal(byte[] val) { |
495 | - return serializer.decode(val); | 495 | + if (val == null) { |
496 | + return null; | ||
497 | + } | ||
498 | + return serializer.decode(val.clone()); | ||
496 | } | 499 | } |
497 | 500 | ||
498 | private Set<byte[]> serializeKeySet(Set<K> keys) { | 501 | private Set<byte[]> serializeKeySet(Set<K> keys) { | ... | ... |
... | @@ -5,6 +5,7 @@ import java.util.ArrayList; | ... | @@ -5,6 +5,7 @@ import java.util.ArrayList; |
5 | import java.util.Arrays; | 5 | import java.util.Arrays; |
6 | import java.util.HashMap; | 6 | import java.util.HashMap; |
7 | import java.util.HashSet; | 7 | import java.util.HashSet; |
8 | +import java.util.LinkedList; | ||
8 | 9 | ||
9 | import org.onlab.onos.cluster.ControllerNode; | 10 | import org.onlab.onos.cluster.ControllerNode; |
10 | import org.onlab.onos.cluster.DefaultControllerNode; | 11 | import org.onlab.onos.cluster.DefaultControllerNode; |
... | @@ -27,12 +28,16 @@ import org.onlab.onos.net.Port; | ... | @@ -27,12 +28,16 @@ import org.onlab.onos.net.Port; |
27 | import org.onlab.onos.net.PortNumber; | 28 | import org.onlab.onos.net.PortNumber; |
28 | import org.onlab.onos.net.device.DefaultDeviceDescription; | 29 | import org.onlab.onos.net.device.DefaultDeviceDescription; |
29 | import org.onlab.onos.net.device.DefaultPortDescription; | 30 | import org.onlab.onos.net.device.DefaultPortDescription; |
31 | +import org.onlab.onos.net.flow.CompletedBatchOperation; | ||
30 | import org.onlab.onos.net.flow.DefaultFlowEntry; | 32 | import org.onlab.onos.net.flow.DefaultFlowEntry; |
31 | import org.onlab.onos.net.flow.DefaultFlowRule; | 33 | import org.onlab.onos.net.flow.DefaultFlowRule; |
32 | import org.onlab.onos.net.flow.DefaultTrafficSelector; | 34 | import org.onlab.onos.net.flow.DefaultTrafficSelector; |
33 | import org.onlab.onos.net.flow.DefaultTrafficTreatment; | 35 | import org.onlab.onos.net.flow.DefaultTrafficTreatment; |
34 | import org.onlab.onos.net.flow.FlowEntry; | 36 | import org.onlab.onos.net.flow.FlowEntry; |
35 | import org.onlab.onos.net.flow.FlowId; | 37 | import org.onlab.onos.net.flow.FlowId; |
38 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry; | ||
39 | +import org.onlab.onos.net.flow.FlowRuleBatchOperation; | ||
40 | +import org.onlab.onos.net.flow.StoredFlowEntry; | ||
36 | import org.onlab.onos.net.flow.criteria.Criteria; | 41 | import org.onlab.onos.net.flow.criteria.Criteria; |
37 | import org.onlab.onos.net.flow.criteria.Criterion; | 42 | import org.onlab.onos.net.flow.criteria.Criterion; |
38 | import org.onlab.onos.net.flow.instructions.Instructions; | 43 | import org.onlab.onos.net.flow.instructions.Instructions; |
... | @@ -79,6 +84,7 @@ public final class KryoNamespaces { | ... | @@ -79,6 +84,7 @@ public final class KryoNamespaces { |
79 | Arrays.asList().getClass(), | 84 | Arrays.asList().getClass(), |
80 | HashMap.class, | 85 | HashMap.class, |
81 | HashSet.class, | 86 | HashSet.class, |
87 | + LinkedList.class, | ||
82 | // | 88 | // |
83 | // | 89 | // |
84 | ControllerNode.State.class, | 90 | ControllerNode.State.class, |
... | @@ -97,6 +103,8 @@ public final class KryoNamespaces { | ... | @@ -97,6 +103,8 @@ public final class KryoNamespaces { |
97 | HostId.class, | 103 | HostId.class, |
98 | HostDescription.class, | 104 | HostDescription.class, |
99 | DefaultHostDescription.class, | 105 | DefaultHostDescription.class, |
106 | + DefaultFlowEntry.class, | ||
107 | + StoredFlowEntry.class, | ||
100 | DefaultFlowRule.class, | 108 | DefaultFlowRule.class, |
101 | DefaultFlowEntry.class, | 109 | DefaultFlowEntry.class, |
102 | FlowEntry.FlowEntryState.class, | 110 | FlowEntry.FlowEntryState.class, |
... | @@ -115,7 +123,11 @@ public final class KryoNamespaces { | ... | @@ -115,7 +123,11 @@ public final class KryoNamespaces { |
115 | DefaultTrafficTreatment.class, | 123 | DefaultTrafficTreatment.class, |
116 | Instructions.DropInstruction.class, | 124 | Instructions.DropInstruction.class, |
117 | Instructions.OutputInstruction.class, | 125 | Instructions.OutputInstruction.class, |
118 | - RoleInfo.class | 126 | + RoleInfo.class, |
127 | + FlowRuleBatchOperation.class, | ||
128 | + CompletedBatchOperation.class, | ||
129 | + FlowRuleBatchEntry.class, | ||
130 | + FlowRuleBatchEntry.FlowRuleOperation.class | ||
119 | ) | 131 | ) |
120 | .register(URI.class, new URISerializer()) | 132 | .register(URI.class, new URISerializer()) |
121 | .register(NodeId.class, new NodeIdSerializer()) | 133 | .register(NodeId.class, new NodeIdSerializer()) | ... | ... |
1 | package org.onlab.onos.store.trivial.impl; | 1 | package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | -import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | 3 | +import com.google.common.base.Function; |
4 | -import static org.slf4j.LoggerFactory.getLogger; | 4 | +import com.google.common.collect.FluentIterable; |
5 | -import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; | 5 | +import com.google.common.util.concurrent.Futures; |
6 | -import java.util.Collections; | ||
7 | -import java.util.HashSet; | ||
8 | -import java.util.List; | ||
9 | -import java.util.Set; | ||
10 | -import java.util.concurrent.ConcurrentHashMap; | ||
11 | -import java.util.concurrent.ConcurrentMap; | ||
12 | -import java.util.concurrent.CopyOnWriteArrayList; | ||
13 | - | ||
14 | import org.apache.felix.scr.annotations.Activate; | 6 | import org.apache.felix.scr.annotations.Activate; |
15 | import org.apache.felix.scr.annotations.Component; | 7 | import org.apache.felix.scr.annotations.Component; |
16 | import org.apache.felix.scr.annotations.Deactivate; | 8 | import org.apache.felix.scr.annotations.Deactivate; |
17 | import org.apache.felix.scr.annotations.Service; | 9 | import org.apache.felix.scr.annotations.Service; |
18 | import org.onlab.onos.ApplicationId; | 10 | import org.onlab.onos.ApplicationId; |
19 | import org.onlab.onos.net.DeviceId; | 11 | import org.onlab.onos.net.DeviceId; |
12 | +import org.onlab.onos.net.flow.CompletedBatchOperation; | ||
20 | import org.onlab.onos.net.flow.DefaultFlowEntry; | 13 | import org.onlab.onos.net.flow.DefaultFlowEntry; |
21 | import org.onlab.onos.net.flow.FlowEntry; | 14 | import org.onlab.onos.net.flow.FlowEntry; |
22 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; | 15 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; |
23 | import org.onlab.onos.net.flow.FlowId; | 16 | import org.onlab.onos.net.flow.FlowId; |
24 | import org.onlab.onos.net.flow.FlowRule; | 17 | import org.onlab.onos.net.flow.FlowRule; |
18 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry; | ||
19 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | ||
20 | +import org.onlab.onos.net.flow.FlowRuleBatchEvent; | ||
21 | +import org.onlab.onos.net.flow.FlowRuleBatchOperation; | ||
22 | +import org.onlab.onos.net.flow.FlowRuleBatchRequest; | ||
25 | import org.onlab.onos.net.flow.FlowRuleEvent; | 23 | import org.onlab.onos.net.flow.FlowRuleEvent; |
26 | import org.onlab.onos.net.flow.FlowRuleEvent.Type; | 24 | import org.onlab.onos.net.flow.FlowRuleEvent.Type; |
27 | import org.onlab.onos.net.flow.FlowRuleStore; | 25 | import org.onlab.onos.net.flow.FlowRuleStore; |
... | @@ -31,8 +29,19 @@ import org.onlab.onos.store.AbstractStore; | ... | @@ -31,8 +29,19 @@ import org.onlab.onos.store.AbstractStore; |
31 | import org.onlab.util.NewConcurrentHashMap; | 29 | import org.onlab.util.NewConcurrentHashMap; |
32 | import org.slf4j.Logger; | 30 | import org.slf4j.Logger; |
33 | 31 | ||
34 | -import com.google.common.base.Function; | 32 | +import java.util.Arrays; |
35 | -import com.google.common.collect.FluentIterable; | 33 | +import java.util.Collections; |
34 | +import java.util.HashSet; | ||
35 | +import java.util.List; | ||
36 | +import java.util.Set; | ||
37 | +import java.util.concurrent.ConcurrentHashMap; | ||
38 | +import java.util.concurrent.ConcurrentMap; | ||
39 | +import java.util.concurrent.CopyOnWriteArrayList; | ||
40 | +import java.util.concurrent.Future; | ||
41 | + | ||
42 | +import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; | ||
43 | +import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | ||
44 | +import static org.slf4j.LoggerFactory.getLogger; | ||
36 | 45 | ||
37 | /** | 46 | /** |
38 | * Manages inventory of flow rules using trivial in-memory implementation. | 47 | * Manages inventory of flow rules using trivial in-memory implementation. |
... | @@ -40,7 +49,7 @@ import com.google.common.collect.FluentIterable; | ... | @@ -40,7 +49,7 @@ import com.google.common.collect.FluentIterable; |
40 | @Component(immediate = true) | 49 | @Component(immediate = true) |
41 | @Service | 50 | @Service |
42 | public class SimpleFlowRuleStore | 51 | public class SimpleFlowRuleStore |
43 | - extends AbstractStore<FlowRuleEvent, FlowRuleStoreDelegate> | 52 | + extends AbstractStore<FlowRuleBatchEvent, FlowRuleStoreDelegate> |
44 | implements FlowRuleStore { | 53 | implements FlowRuleStore { |
45 | 54 | ||
46 | private final Logger log = getLogger(getClass()); | 55 | private final Logger log = getLogger(getClass()); |
... | @@ -148,12 +157,11 @@ public class SimpleFlowRuleStore | ... | @@ -148,12 +157,11 @@ public class SimpleFlowRuleStore |
148 | } | 157 | } |
149 | 158 | ||
150 | @Override | 159 | @Override |
151 | - public boolean storeFlowRule(FlowRule rule) { | 160 | + public void storeFlowRule(FlowRule rule) { |
152 | - final boolean added = storeFlowRuleInternal(rule); | 161 | + storeFlowRuleInternal(rule); |
153 | - return added; | ||
154 | } | 162 | } |
155 | 163 | ||
156 | - private boolean storeFlowRuleInternal(FlowRule rule) { | 164 | + private void storeFlowRuleInternal(FlowRule rule) { |
157 | StoredFlowEntry f = new DefaultFlowEntry(rule); | 165 | StoredFlowEntry f = new DefaultFlowEntry(rule); |
158 | final DeviceId did = f.deviceId(); | 166 | final DeviceId did = f.deviceId(); |
159 | final FlowId fid = f.id(); | 167 | final FlowId fid = f.id(); |
... | @@ -162,19 +170,20 @@ public class SimpleFlowRuleStore | ... | @@ -162,19 +170,20 @@ public class SimpleFlowRuleStore |
162 | for (StoredFlowEntry fe : existing) { | 170 | for (StoredFlowEntry fe : existing) { |
163 | if (fe.equals(rule)) { | 171 | if (fe.equals(rule)) { |
164 | // was already there? ignore | 172 | // was already there? ignore |
165 | - return false; | 173 | + return; |
166 | } | 174 | } |
167 | } | 175 | } |
168 | // new flow rule added | 176 | // new flow rule added |
169 | existing.add(f); | 177 | existing.add(f); |
170 | - // TODO: Should we notify only if it's "remote" event? | 178 | + notifyDelegate(FlowRuleBatchEvent.requested( |
171 | - //notifyDelegate(new FlowRuleEvent(Type.RULE_ADD_REQUESTED, rule)); | 179 | + new FlowRuleBatchRequest(1, /* FIXME generate something */ |
172 | - return true; | 180 | + Arrays.<FlowEntry>asList(f), |
181 | + Collections.<FlowEntry>emptyList()))); | ||
173 | } | 182 | } |
174 | } | 183 | } |
175 | 184 | ||
176 | @Override | 185 | @Override |
177 | - public boolean deleteFlowRule(FlowRule rule) { | 186 | + public void deleteFlowRule(FlowRule rule) { |
178 | 187 | ||
179 | List<StoredFlowEntry> entries = getFlowEntries(rule.deviceId(), rule.id()); | 188 | List<StoredFlowEntry> entries = getFlowEntries(rule.deviceId(), rule.id()); |
180 | 189 | ||
... | @@ -184,14 +193,17 @@ public class SimpleFlowRuleStore | ... | @@ -184,14 +193,17 @@ public class SimpleFlowRuleStore |
184 | synchronized (entry) { | 193 | synchronized (entry) { |
185 | entry.setState(FlowEntryState.PENDING_REMOVE); | 194 | entry.setState(FlowEntryState.PENDING_REMOVE); |
186 | // TODO: Should we notify only if it's "remote" event? | 195 | // TODO: Should we notify only if it's "remote" event? |
187 | - //notifyDelegate(new FlowRuleEvent(Type.RULE_REMOVE_REQUESTED, rule)); | 196 | + notifyDelegate(FlowRuleBatchEvent.requested( |
188 | - return true; | 197 | + new FlowRuleBatchRequest(1, /* FIXME generate something */ |
198 | + Collections.<FlowEntry>emptyList(), | ||
199 | + Arrays.<FlowEntry>asList(entry)))); | ||
189 | } | 200 | } |
190 | } | 201 | } |
191 | } | 202 | } |
192 | } | 203 | } |
204 | + | ||
205 | + | ||
193 | //log.warn("Cannot find rule {}", rule); | 206 | //log.warn("Cannot find rule {}", rule); |
194 | - return false; | ||
195 | } | 207 | } |
196 | 208 | ||
197 | @Override | 209 | @Override |
... | @@ -237,4 +249,24 @@ public class SimpleFlowRuleStore | ... | @@ -237,4 +249,24 @@ public class SimpleFlowRuleStore |
237 | } | 249 | } |
238 | return null; | 250 | return null; |
239 | } | 251 | } |
252 | + | ||
253 | + @Override | ||
254 | + public Future<CompletedBatchOperation> storeBatch( | ||
255 | + FlowRuleBatchOperation batchOperation) { | ||
256 | + for (FlowRuleBatchEntry entry : batchOperation.getOperations()) { | ||
257 | + if (entry.getOperator().equals(FlowRuleOperation.ADD)) { | ||
258 | + storeFlowRule(entry.getTarget()); | ||
259 | + } else if (entry.getOperator().equals(FlowRuleOperation.REMOVE)) { | ||
260 | + deleteFlowRule(entry.getTarget()); | ||
261 | + } else { | ||
262 | + throw new UnsupportedOperationException("Unsupported operation type"); | ||
263 | + } | ||
264 | + } | ||
265 | + return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowEntry>emptySet())); | ||
266 | + } | ||
267 | + | ||
268 | + @Override | ||
269 | + public void batchOperationComplete(FlowRuleBatchEvent event) { | ||
270 | + notifyDelegate(event); | ||
271 | + } | ||
240 | } | 272 | } | ... | ... |
... | @@ -269,7 +269,7 @@ public class SimpleHostStore | ... | @@ -269,7 +269,7 @@ public class SimpleHostStore |
269 | } | 269 | } |
270 | 270 | ||
271 | // Auxiliary extension to allow location to mutate. | 271 | // Auxiliary extension to allow location to mutate. |
272 | - private class StoredHost extends DefaultHost { | 272 | + private static final class StoredHost extends DefaultHost { |
273 | private HostLocation location; | 273 | private HostLocation location; |
274 | 274 | ||
275 | /** | 275 | /** | ... | ... |
docs/external.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
5 | + <modelVersion>4.0.0</modelVersion> | ||
6 | + | ||
7 | + <prerequisites> | ||
8 | + <maven>3.0.0</maven> | ||
9 | + </prerequisites> | ||
10 | + | ||
11 | + <parent> | ||
12 | + <groupId>org.onlab.onos</groupId> | ||
13 | + <artifactId>onos</artifactId> | ||
14 | + <version>1.0.0-SNAPSHOT</version> | ||
15 | + <relativePath>../pom.xml</relativePath> | ||
16 | + </parent> | ||
17 | + | ||
18 | + <artifactId>onos-docs-external</artifactId> | ||
19 | + <packaging>pom</packaging> | ||
20 | + | ||
21 | + <description>ONOS Java API documentation</description> | ||
22 | + | ||
23 | + <modules> | ||
24 | + <module>..</module> | ||
25 | + </modules> | ||
26 | + | ||
27 | + <url>http://onlab.us/</url> | ||
28 | + | ||
29 | + <build> | ||
30 | + <plugins> | ||
31 | + <plugin> | ||
32 | + <groupId>org.apache.maven.plugins</groupId> | ||
33 | + <artifactId>maven-javadoc-plugin</artifactId> | ||
34 | + <version>2.10.1</version> | ||
35 | + <configuration> | ||
36 | + <show>package</show> | ||
37 | + <excludePackageNames>org.onlab.thirdparty:*.impl:*.impl.*:org.onlab.onos.provider.*:org.onlab.onos.gui:org.onlab.onos.rest:org.onlab.onos.cli*:org.onlab.onos.tvue:org.onlab.onos.foo:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.optical:org.onlab.onos.config:org.onlab.onos.calendar:org.onlab.onos.sdnip*:org.onlab.onos.metrics</excludePackageNames> | ||
38 | + <docfilessubdirs>true</docfilessubdirs> | ||
39 | + <doctitle>ONOS Java API</doctitle> | ||
40 | + <groups> | ||
41 | + <group> | ||
42 | + <title>Network Model & Services</title> | ||
43 | + <packages> | ||
44 | + org.onlab.onos:org.onlab.onos.* | ||
45 | + </packages> | ||
46 | + </group> | ||
47 | + <group> | ||
48 | + <title>Utilities</title> | ||
49 | + <packages> | ||
50 | + org.onlab.* | ||
51 | + </packages> | ||
52 | + </group> | ||
53 | + </groups> | ||
54 | + </configuration> | ||
55 | + </plugin> | ||
56 | + </plugins> | ||
57 | + </build> | ||
58 | + | ||
59 | +</project> |
docs/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
5 | + <modelVersion>4.0.0</modelVersion> | ||
6 | + | ||
7 | + <prerequisites> | ||
8 | + <maven>3.0.0</maven> | ||
9 | + </prerequisites> | ||
10 | + | ||
11 | + <parent> | ||
12 | + <groupId>org.onlab.onos</groupId> | ||
13 | + <artifactId>onos</artifactId> | ||
14 | + <version>1.0.0-SNAPSHOT</version> | ||
15 | + <relativePath>../pom.xml</relativePath> | ||
16 | + </parent> | ||
17 | + | ||
18 | + <artifactId>onos-docs</artifactId> | ||
19 | + <packaging>pom</packaging> | ||
20 | + | ||
21 | + <description>ONOS Java API documentation</description> | ||
22 | + | ||
23 | + <modules> | ||
24 | + <module>..</module> | ||
25 | + </modules> | ||
26 | + | ||
27 | + <url>http://onlab.us/</url> | ||
28 | + | ||
29 | + <build> | ||
30 | + <plugins> | ||
31 | + <plugin> | ||
32 | + <groupId>org.apache.maven.plugins</groupId> | ||
33 | + <artifactId>maven-javadoc-plugin</artifactId> | ||
34 | + <version>2.10.1</version> | ||
35 | + <configuration> | ||
36 | + <show>package</show> | ||
37 | + <docfilessubdirs>true</docfilessubdirs> | ||
38 | + <doctitle>ONOS Java API</doctitle> | ||
39 | + <groups> | ||
40 | + <group> | ||
41 | + <title>Network Model & Services</title> | ||
42 | + <packages> | ||
43 | + org.onlab.onos:org.onlab.onos.* | ||
44 | + </packages> | ||
45 | + </group> | ||
46 | + <group> | ||
47 | + <title>Core Subsystems</title> | ||
48 | + <packages> | ||
49 | + org.onlab.onos.impl:org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl:org.onlab.onos.net.proxyarp.impl:org.onlab.onos.mastership.impl:org.onlab.onos.json:org.onlab.onos.json.*:org.onlab.onos.provider.host.impl:org.onlab.onos.provider.lldp.impl:org.onlab.onos.net.statistic.impl | ||
50 | + </packages> | ||
51 | + </group> | ||
52 | + <group> | ||
53 | + <title>OpenFlow Providers & Controller | ||
54 | + </title> | ||
55 | + <packages> | ||
56 | + org.onlab.onos.provider.of.*:org.onlab.onos.openflow.* | ||
57 | + </packages> | ||
58 | + </group> | ||
59 | + <group> | ||
60 | + <title>Utilities</title> | ||
61 | + <packages> | ||
62 | + org.onlab.* | ||
63 | + </packages> | ||
64 | + </group> | ||
65 | + <group> | ||
66 | + <title>GUI, REST & Command-Line</title> | ||
67 | + <packages> | ||
68 | + org.onlab.onos.gui:org.onlab.onos.rest:org.onlab.onos.cli:org.onlab.onos.gui.*:org.onlab.onos.rest.*:org.onlab.onos.cli.* | ||
69 | + </packages> | ||
70 | + </group> | ||
71 | + <group> | ||
72 | + <title>Sample Applications</title> | ||
73 | + <packages> | ||
74 | + org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.foo:org.onlab.onos.calendar:org.onlab.onos.sdnip:org.onlab.onos.sdnip.*:org.onlab.onos.optical:org.onlab.onos.optical.*:org.onlab.onos.metrics.*:org.onlab.onos.config | ||
75 | + </packages> | ||
76 | + </group> | ||
77 | + </groups> | ||
78 | + <excludePackageNames>org.onlab.thirdparty | ||
79 | + </excludePackageNames> | ||
80 | + </configuration> | ||
81 | + </plugin> | ||
82 | + </plugins> | ||
83 | + </build> | ||
84 | + | ||
85 | +</project> |

68.4 KB
... | @@ -35,7 +35,7 @@ | ... | @@ -35,7 +35,7 @@ |
35 | <bundle>mvn:io.netty/netty-transport-native-epoll/4.0.23.Final</bundle> | 35 | <bundle>mvn:io.netty/netty-transport-native-epoll/4.0.23.Final</bundle> |
36 | <bundle>mvn:commons-pool/commons-pool/1.6</bundle> | 36 | <bundle>mvn:commons-pool/commons-pool/1.6</bundle> |
37 | 37 | ||
38 | - <bundle>mvn:com.hazelcast/hazelcast/3.3</bundle> | 38 | + <bundle>mvn:com.hazelcast/hazelcast/3.3.2</bundle> |
39 | <bundle>mvn:io.dropwizard.metrics/metrics-core/3.1.0</bundle> | 39 | <bundle>mvn:io.dropwizard.metrics/metrics-core/3.1.0</bundle> |
40 | <bundle>mvn:io.dropwizard.metrics/metrics-json/3.1.0</bundle> | 40 | <bundle>mvn:io.dropwizard.metrics/metrics-json/3.1.0</bundle> |
41 | <bundle>mvn:com.eclipsesource.minimal-json/minimal-json/0.9.1</bundle> | 41 | <bundle>mvn:com.eclipsesource.minimal-json/minimal-json/0.9.1</bundle> | ... | ... |
... | @@ -30,7 +30,7 @@ | ... | @@ -30,7 +30,7 @@ |
30 | <groupId>org.projectfloodlight</groupId> | 30 | <groupId>org.projectfloodlight</groupId> |
31 | <artifactId>openflowj</artifactId> | 31 | <artifactId>openflowj</artifactId> |
32 | <!-- FIXME once experimenter gets merged to upstream --> | 32 | <!-- FIXME once experimenter gets merged to upstream --> |
33 | - <version>0.3.8-optical_experimenter3</version> | 33 | + <version>0.3.8-optical_experimenter4</version> |
34 | </dependency> | 34 | </dependency> |
35 | <dependency> | 35 | <dependency> |
36 | <groupId>io.netty</groupId> | 36 | <groupId>io.netty</groupId> | ... | ... |
1 | package org.onlab.onos.openflow.controller; | 1 | package org.onlab.onos.openflow.controller; |
2 | 2 | ||
3 | + | ||
4 | +import java.util.Collections; | ||
5 | +import java.util.concurrent.atomic.AtomicBoolean; | ||
6 | + | ||
3 | import org.onlab.packet.Ethernet; | 7 | import org.onlab.packet.Ethernet; |
4 | import org.projectfloodlight.openflow.protocol.OFPacketIn; | 8 | import org.projectfloodlight.openflow.protocol.OFPacketIn; |
5 | import org.projectfloodlight.openflow.protocol.OFPacketOut; | 9 | import org.projectfloodlight.openflow.protocol.OFPacketOut; |
... | @@ -9,9 +13,6 @@ import org.projectfloodlight.openflow.protocol.match.MatchField; | ... | @@ -9,9 +13,6 @@ import org.projectfloodlight.openflow.protocol.match.MatchField; |
9 | import org.projectfloodlight.openflow.types.OFBufferId; | 13 | import org.projectfloodlight.openflow.types.OFBufferId; |
10 | import org.projectfloodlight.openflow.types.OFPort; | 14 | import org.projectfloodlight.openflow.types.OFPort; |
11 | 15 | ||
12 | -import java.util.Collections; | ||
13 | -import java.util.concurrent.atomic.AtomicBoolean; | ||
14 | - | ||
15 | public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext { | 16 | public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext { |
16 | 17 | ||
17 | private final AtomicBoolean free = new AtomicBoolean(true); | 18 | private final AtomicBoolean free = new AtomicBoolean(true); | ... | ... |
... | @@ -4,6 +4,10 @@ | ... | @@ -4,6 +4,10 @@ |
4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | 4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
5 | <modelVersion>4.0.0</modelVersion> | 5 | <modelVersion>4.0.0</modelVersion> |
6 | 6 | ||
7 | + <prerequisites> | ||
8 | + <maven>3.0.0</maven> | ||
9 | + </prerequisites> | ||
10 | + | ||
7 | <groupId>org.onlab.onos</groupId> | 11 | <groupId>org.onlab.onos</groupId> |
8 | <artifactId>onos</artifactId> | 12 | <artifactId>onos</artifactId> |
9 | <packaging>pom</packaging> | 13 | <packaging>pom</packaging> |
... | @@ -28,7 +32,6 @@ | ... | @@ -28,7 +32,6 @@ |
28 | 32 | ||
29 | <licenses> | 33 | <licenses> |
30 | <license> | 34 | <license> |
31 | - <!-- TODO: Is this really our license scheme? --> | ||
32 | <name>Apache License, Version 2.0</name> | 35 | <name>Apache License, Version 2.0</name> |
33 | <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> | 36 | <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> |
34 | </license> | 37 | </license> |
... | @@ -192,7 +195,7 @@ | ... | @@ -192,7 +195,7 @@ |
192 | <dependency> | 195 | <dependency> |
193 | <groupId>com.hazelcast</groupId> | 196 | <groupId>com.hazelcast</groupId> |
194 | <artifactId>hazelcast</artifactId> | 197 | <artifactId>hazelcast</artifactId> |
195 | - <version>3.3</version> | 198 | + <version>3.3.2</version> |
196 | </dependency> | 199 | </dependency> |
197 | <dependency> | 200 | <dependency> |
198 | <groupId>com.eclipsesource.minimal-json</groupId> | 201 | <groupId>com.eclipsesource.minimal-json</groupId> |
... | @@ -528,59 +531,6 @@ | ... | @@ -528,59 +531,6 @@ |
528 | </execution> | 531 | </execution> |
529 | </executions> | 532 | </executions> |
530 | </plugin> | 533 | </plugin> |
531 | - | ||
532 | - <plugin> | ||
533 | - <groupId>org.apache.maven.plugins</groupId> | ||
534 | - <artifactId>maven-javadoc-plugin</artifactId> | ||
535 | - <version>2.10.1</version> | ||
536 | - <configuration> | ||
537 | - <show>package</show> | ||
538 | - <docfilessubdirs>true</docfilessubdirs> | ||
539 | - <doctitle>ONOS Java API</doctitle> | ||
540 | - <groups> | ||
541 | - <group> | ||
542 | - <title>Network Model & Services</title> | ||
543 | - <packages> | ||
544 | - org.onlab.onos:org.onlab.onos.* | ||
545 | - </packages> | ||
546 | - </group> | ||
547 | - <group> | ||
548 | - <title>Core Subsystems</title> | ||
549 | - <packages> | ||
550 | - org.onlab.onos.impl:org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl:org.onlab.onos.net.proxyarp.impl:org.onlab.onos.mastership.impl:org.onlab.onos.json:org.onlab.onos.json.*:org.onlab.onos.provider.host.impl:org.onlab.onos.provider.lldp.impl:org.onlab.onos.net.statistic.impl | ||
551 | - </packages> | ||
552 | - </group> | ||
553 | - <group> | ||
554 | - <title>OpenFlow Providers & Controller | ||
555 | - </title> | ||
556 | - <packages> | ||
557 | - org.onlab.onos.provider.of.*:org.onlab.onos.openflow.* | ||
558 | - </packages> | ||
559 | - </group> | ||
560 | - <group> | ||
561 | - <title>Utilities</title> | ||
562 | - <packages> | ||
563 | - org.onlab.* | ||
564 | - </packages> | ||
565 | - </group> | ||
566 | - <group> | ||
567 | - <title>GUI, REST & Command-Line</title> | ||
568 | - <packages> | ||
569 | - org.onlab.onos.gui:org.onlab.onos.rest:org.onlab.onos.cli:org.onlab.onos.gui.*:org.onlab.onos.rest.*:org.onlab.onos.cli.* | ||
570 | - </packages> | ||
571 | - </group> | ||
572 | - <group> | ||
573 | - <title>Sample Applications</title> | ||
574 | - <packages> | ||
575 | - org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.foo:org.onlab.onos.calendar:org.onlab.onos.sdnip:org.onlab.onos.sdnip.*:org.onlab.onos.optical:org.onlab.onos.optical.*:org.onlab.onos.metrics.* | ||
576 | - </packages> | ||
577 | - </group> | ||
578 | - </groups> | ||
579 | - <excludePackageNames>org.onlab.thirdparty | ||
580 | - </excludePackageNames> | ||
581 | - </configuration> | ||
582 | - </plugin> | ||
583 | - | ||
584 | </plugins> | 534 | </plugins> |
585 | </build> | 535 | </build> |
586 | 536 | ||
... | @@ -607,10 +557,6 @@ | ... | @@ -607,10 +557,6 @@ |
607 | </rulesets> | 557 | </rulesets> |
608 | </configuration> | 558 | </configuration> |
609 | </plugin> | 559 | </plugin> |
610 | - | ||
611 | </plugins> | 560 | </plugins> |
612 | </reporting> | 561 | </reporting> |
613 | - <prerequisites> | ||
614 | - <maven>3.0.0</maven> | ||
615 | - </prerequisites> | ||
616 | </project> | 562 | </project> | ... | ... |
... | @@ -217,7 +217,7 @@ public class LinkDiscovery implements TimerTask { | ... | @@ -217,7 +217,7 @@ public class LinkDiscovery implements TimerTask { |
217 | final PortNumber srcPort = PortNumber.portNumber(onoslldp.getPort()); | 217 | final PortNumber srcPort = PortNumber.portNumber(onoslldp.getPort()); |
218 | final DeviceId srcDeviceId = DeviceId.deviceId(onoslldp.getDeviceString()); | 218 | final DeviceId srcDeviceId = DeviceId.deviceId(onoslldp.getDeviceString()); |
219 | final DeviceId dstDeviceId = context.inPacket().receivedFrom().deviceId(); | 219 | final DeviceId dstDeviceId = context.inPacket().receivedFrom().deviceId(); |
220 | - this.ackProbe(srcPort.toLong()); | 220 | + this.ackProbe(dstPort.toLong()); |
221 | ConnectPoint src = new ConnectPoint(srcDeviceId, srcPort); | 221 | ConnectPoint src = new ConnectPoint(srcDeviceId, srcPort); |
222 | ConnectPoint dst = new ConnectPoint(dstDeviceId, dstPort); | 222 | ConnectPoint dst = new ConnectPoint(dstDeviceId, dstPort); |
223 | 223 | ||
... | @@ -245,7 +245,7 @@ public class LinkDiscovery implements TimerTask { | ... | @@ -245,7 +245,7 @@ public class LinkDiscovery implements TimerTask { |
245 | */ | 245 | */ |
246 | @Override | 246 | @Override |
247 | public void run(final Timeout t) { | 247 | public void run(final Timeout t) { |
248 | - this.log.debug("sending probes"); | 248 | + this.log.trace("sending probes"); |
249 | synchronized (this) { | 249 | synchronized (this) { |
250 | final Iterator<Long> fastIterator = this.fastPorts.iterator(); | 250 | final Iterator<Long> fastIterator = this.fastPorts.iterator(); |
251 | Long portNumber; | 251 | Long portNumber; |
... | @@ -256,7 +256,7 @@ public class LinkDiscovery implements TimerTask { | ... | @@ -256,7 +256,7 @@ public class LinkDiscovery implements TimerTask { |
256 | .getAndIncrement(); | 256 | .getAndIncrement(); |
257 | 257 | ||
258 | if (probeCount < LinkDiscovery.MAX_PROBE_COUNT) { | 258 | if (probeCount < LinkDiscovery.MAX_PROBE_COUNT) { |
259 | - this.log.debug("sending fast probe to port"); | 259 | + this.log.trace("sending fast probe to port"); |
260 | sendProbes(portNumber); | 260 | sendProbes(portNumber); |
261 | } else { | 261 | } else { |
262 | // Update fast and slow ports | 262 | // Update fast and slow ports |
... | @@ -278,7 +278,7 @@ public class LinkDiscovery implements TimerTask { | ... | @@ -278,7 +278,7 @@ public class LinkDiscovery implements TimerTask { |
278 | Iterator<Long> slowIterator = this.slowPorts.iterator(); | 278 | Iterator<Long> slowIterator = this.slowPorts.iterator(); |
279 | while (slowIterator.hasNext()) { | 279 | while (slowIterator.hasNext()) { |
280 | portNumber = slowIterator.next(); | 280 | portNumber = slowIterator.next(); |
281 | - this.log.debug("sending slow probe to port {}", portNumber); | 281 | + this.log.trace("sending slow probe to port {}", portNumber); |
282 | 282 | ||
283 | sendProbes(portNumber); | 283 | sendProbes(portNumber); |
284 | 284 | ... | ... |
... | @@ -23,6 +23,8 @@ import org.projectfloodlight.openflow.protocol.OFFlowRemoved; | ... | @@ -23,6 +23,8 @@ import org.projectfloodlight.openflow.protocol.OFFlowRemoved; |
23 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; | 23 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; |
24 | import org.projectfloodlight.openflow.protocol.OFInstructionType; | 24 | import org.projectfloodlight.openflow.protocol.OFInstructionType; |
25 | import org.projectfloodlight.openflow.protocol.action.OFAction; | 25 | import org.projectfloodlight.openflow.protocol.action.OFAction; |
26 | +import org.projectfloodlight.openflow.protocol.action.OFActionCircuit; | ||
27 | +import org.projectfloodlight.openflow.protocol.action.OFActionExperimenter; | ||
26 | import org.projectfloodlight.openflow.protocol.action.OFActionOutput; | 28 | import org.projectfloodlight.openflow.protocol.action.OFActionOutput; |
27 | import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst; | 29 | import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst; |
28 | import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc; | 30 | import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc; |
... | @@ -34,6 +36,7 @@ import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; | ... | @@ -34,6 +36,7 @@ import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; |
34 | import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions; | 36 | import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions; |
35 | import org.projectfloodlight.openflow.protocol.match.Match; | 37 | import org.projectfloodlight.openflow.protocol.match.Match; |
36 | import org.projectfloodlight.openflow.protocol.match.MatchField; | 38 | import org.projectfloodlight.openflow.protocol.match.MatchField; |
39 | +import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigidBasic; | ||
37 | import org.projectfloodlight.openflow.types.IPv4Address; | 40 | import org.projectfloodlight.openflow.types.IPv4Address; |
38 | import org.projectfloodlight.openflow.types.Masked; | 41 | import org.projectfloodlight.openflow.types.Masked; |
39 | import org.slf4j.Logger; | 42 | import org.slf4j.Logger; |
... | @@ -166,6 +169,15 @@ public class FlowEntryBuilder { | ... | @@ -166,6 +169,15 @@ public class FlowEntryBuilder { |
166 | builder.setIpSrc(IpPrefix.valueOf(si.getInt())); | 169 | builder.setIpSrc(IpPrefix.valueOf(si.getInt())); |
167 | } | 170 | } |
168 | break; | 171 | break; |
172 | + case EXPERIMENTER: | ||
173 | + OFActionExperimenter exp = (OFActionExperimenter) act; | ||
174 | + if (exp.getExperimenter() == 0x80005A06) { | ||
175 | + OFActionCircuit ct = (OFActionCircuit) exp; | ||
176 | + builder.setLambda(((OFOxmOchSigidBasic) ct.getField()).getValue().getChannelNumber()); | ||
177 | + } else { | ||
178 | + log.warn("Unsupported OFActionExperimenter {}", exp.getExperimenter()); | ||
179 | + } | ||
180 | + break; | ||
169 | case SET_TP_DST: | 181 | case SET_TP_DST: |
170 | case SET_TP_SRC: | 182 | case SET_TP_SRC: |
171 | case POP_MPLS: | 183 | case POP_MPLS: |
... | @@ -188,7 +200,7 @@ public class FlowEntryBuilder { | ... | @@ -188,7 +200,7 @@ public class FlowEntryBuilder { |
188 | case DEC_MPLS_TTL: | 200 | case DEC_MPLS_TTL: |
189 | case DEC_NW_TTL: | 201 | case DEC_NW_TTL: |
190 | case ENQUEUE: | 202 | case ENQUEUE: |
191 | - case EXPERIMENTER: | 203 | + |
192 | case GROUP: | 204 | case GROUP: |
193 | default: | 205 | default: |
194 | log.warn("Action type {} not yet implemented.", act.getType()); | 206 | log.warn("Action type {} not yet implemented.", act.getType()); |
... | @@ -268,6 +280,10 @@ public class FlowEntryBuilder { | ... | @@ -268,6 +280,10 @@ public class FlowEntryBuilder { |
268 | case TCP_SRC: | 280 | case TCP_SRC: |
269 | builder.matchTcpSrc((short) match.get(MatchField.TCP_SRC).getPort()); | 281 | builder.matchTcpSrc((short) match.get(MatchField.TCP_SRC).getPort()); |
270 | break; | 282 | break; |
283 | + case OCH_SIGID: | ||
284 | + builder.matchLambda(match.get(MatchField.OCH_SIGID).getChannelNumber()); | ||
285 | + break; | ||
286 | + case OCH_SIGTYPE_BASIC: | ||
271 | case ARP_OP: | 287 | case ARP_OP: |
272 | case ARP_SHA: | 288 | case ARP_SHA: |
273 | case ARP_SPA: | 289 | case ARP_SPA: | ... | ... |
... | @@ -14,6 +14,7 @@ import org.onlab.onos.net.flow.criteria.Criteria.EthCriterion; | ... | @@ -14,6 +14,7 @@ import org.onlab.onos.net.flow.criteria.Criteria.EthCriterion; |
14 | import org.onlab.onos.net.flow.criteria.Criteria.EthTypeCriterion; | 14 | import org.onlab.onos.net.flow.criteria.Criteria.EthTypeCriterion; |
15 | import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion; | 15 | import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion; |
16 | import org.onlab.onos.net.flow.criteria.Criteria.IPProtocolCriterion; | 16 | import org.onlab.onos.net.flow.criteria.Criteria.IPProtocolCriterion; |
17 | +import org.onlab.onos.net.flow.criteria.Criteria.LambdaCriterion; | ||
17 | import org.onlab.onos.net.flow.criteria.Criteria.PortCriterion; | 18 | import org.onlab.onos.net.flow.criteria.Criteria.PortCriterion; |
18 | import org.onlab.onos.net.flow.criteria.Criteria.TcpPortCriterion; | 19 | import org.onlab.onos.net.flow.criteria.Criteria.TcpPortCriterion; |
19 | import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion; | 20 | import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion; |
... | @@ -21,6 +22,8 @@ import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion; | ... | @@ -21,6 +22,8 @@ import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion; |
21 | import org.onlab.onos.net.flow.criteria.Criterion; | 22 | import org.onlab.onos.net.flow.criteria.Criterion; |
22 | import org.onlab.onos.net.flow.instructions.Instruction; | 23 | import org.onlab.onos.net.flow.instructions.Instruction; |
23 | import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction; | 24 | import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction; |
25 | +import org.onlab.onos.net.flow.instructions.L0ModificationInstruction; | ||
26 | +import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction; | ||
24 | import org.onlab.onos.net.flow.instructions.L2ModificationInstruction; | 27 | import org.onlab.onos.net.flow.instructions.L2ModificationInstruction; |
25 | import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; | 28 | import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; |
26 | import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; | 29 | import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; |
... | @@ -35,6 +38,7 @@ import org.projectfloodlight.openflow.protocol.OFFlowModFlags; | ... | @@ -35,6 +38,7 @@ import org.projectfloodlight.openflow.protocol.OFFlowModFlags; |
35 | import org.projectfloodlight.openflow.protocol.action.OFAction; | 38 | import org.projectfloodlight.openflow.protocol.action.OFAction; |
36 | import org.projectfloodlight.openflow.protocol.match.Match; | 39 | import org.projectfloodlight.openflow.protocol.match.Match; |
37 | import org.projectfloodlight.openflow.protocol.match.MatchField; | 40 | import org.projectfloodlight.openflow.protocol.match.MatchField; |
41 | +import org.projectfloodlight.openflow.types.CircuitSignalID; | ||
38 | import org.projectfloodlight.openflow.types.EthType; | 42 | import org.projectfloodlight.openflow.types.EthType; |
39 | import org.projectfloodlight.openflow.types.IPv4Address; | 43 | import org.projectfloodlight.openflow.types.IPv4Address; |
40 | import org.projectfloodlight.openflow.types.IpProtocol; | 44 | import org.projectfloodlight.openflow.types.IpProtocol; |
... | @@ -137,6 +141,9 @@ public class FlowModBuilder { | ... | @@ -137,6 +141,9 @@ public class FlowModBuilder { |
137 | case DROP: | 141 | case DROP: |
138 | log.warn("Saw drop action; assigning drop action"); | 142 | log.warn("Saw drop action; assigning drop action"); |
139 | return new LinkedList<>(); | 143 | return new LinkedList<>(); |
144 | + case L0MODIFICATION: | ||
145 | + acts.add(buildL0Modification(i)); | ||
146 | + break; | ||
140 | case L2MODIFICATION: | 147 | case L2MODIFICATION: |
141 | acts.add(buildL2Modification(i)); | 148 | acts.add(buildL2Modification(i)); |
142 | break; | 149 | break; |
... | @@ -157,6 +164,20 @@ public class FlowModBuilder { | ... | @@ -157,6 +164,20 @@ public class FlowModBuilder { |
157 | return acts; | 164 | return acts; |
158 | } | 165 | } |
159 | 166 | ||
167 | + private OFAction buildL0Modification(Instruction i) { | ||
168 | + L0ModificationInstruction l0m = (L0ModificationInstruction) i; | ||
169 | + switch (l0m.subtype()) { | ||
170 | + case LAMBDA: | ||
171 | + ModLambdaInstruction ml = (ModLambdaInstruction) i; | ||
172 | + return factory.actions().circuit(factory.oxms().ochSigidBasic( | ||
173 | + new CircuitSignalID((byte) 1, (byte) 2, ml.lambda(), (short) 1))); | ||
174 | + default: | ||
175 | + log.warn("Unimplemented action type {}.", l0m.subtype()); | ||
176 | + break; | ||
177 | + } | ||
178 | + return null; | ||
179 | + } | ||
180 | + | ||
160 | private OFAction buildL3Modification(Instruction i) { | 181 | private OFAction buildL3Modification(Instruction i) { |
161 | L3ModificationInstruction l3m = (L3ModificationInstruction) i; | 182 | L3ModificationInstruction l3m = (L3ModificationInstruction) i; |
162 | ModIPInstruction ip; | 183 | ModIPInstruction ip; |
... | @@ -261,6 +282,11 @@ public class FlowModBuilder { | ... | @@ -261,6 +282,11 @@ public class FlowModBuilder { |
261 | tp = (TcpPortCriterion) c; | 282 | tp = (TcpPortCriterion) c; |
262 | mBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(tp.tcpPort())); | 283 | mBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(tp.tcpPort())); |
263 | break; | 284 | break; |
285 | + case OCH_SIGID: | ||
286 | + LambdaCriterion lc = (LambdaCriterion) c; | ||
287 | + mBuilder.setExact(MatchField.OCH_SIGID, | ||
288 | + new CircuitSignalID((byte) 1, (byte) 2, lc.lambda(), (short) 1)); | ||
289 | + break; | ||
264 | case ARP_OP: | 290 | case ARP_OP: |
265 | case ARP_SHA: | 291 | case ARP_SHA: |
266 | case ARP_SPA: | 292 | case ARP_SPA: | ... | ... |
providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
... | @@ -10,7 +10,7 @@ import java.util.Set; | ... | @@ -10,7 +10,7 @@ import java.util.Set; |
10 | import java.util.concurrent.ConcurrentHashMap; | 10 | import java.util.concurrent.ConcurrentHashMap; |
11 | import java.util.concurrent.CountDownLatch; | 11 | import java.util.concurrent.CountDownLatch; |
12 | import java.util.concurrent.ExecutionException; | 12 | import java.util.concurrent.ExecutionException; |
13 | -import java.util.concurrent.Future; | 13 | +import java.util.concurrent.Executor; |
14 | import java.util.concurrent.TimeUnit; | 14 | import java.util.concurrent.TimeUnit; |
15 | import java.util.concurrent.TimeoutException; | 15 | import java.util.concurrent.TimeoutException; |
16 | import java.util.concurrent.atomic.AtomicBoolean; | 16 | import java.util.concurrent.atomic.AtomicBoolean; |
... | @@ -69,9 +69,11 @@ import org.projectfloodlight.openflow.types.U32; | ... | @@ -69,9 +69,11 @@ import org.projectfloodlight.openflow.types.U32; |
69 | import org.slf4j.Logger; | 69 | import org.slf4j.Logger; |
70 | 70 | ||
71 | import com.google.common.collect.ArrayListMultimap; | 71 | import com.google.common.collect.ArrayListMultimap; |
72 | -import com.google.common.collect.Lists; | ||
73 | import com.google.common.collect.Maps; | 72 | import com.google.common.collect.Maps; |
74 | import com.google.common.collect.Multimap; | 73 | import com.google.common.collect.Multimap; |
74 | +import com.google.common.collect.Sets; | ||
75 | +import com.google.common.util.concurrent.ExecutionList; | ||
76 | +import com.google.common.util.concurrent.ListenableFuture; | ||
75 | 77 | ||
76 | /** | 78 | /** |
77 | * Provider which uses an OpenFlow controller to detect network | 79 | * Provider which uses an OpenFlow controller to detect network |
... | @@ -97,6 +99,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -97,6 +99,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
97 | 99 | ||
98 | private final InternalFlowProvider listener = new InternalFlowProvider(); | 100 | private final InternalFlowProvider listener = new InternalFlowProvider(); |
99 | 101 | ||
102 | + // FIXME: This should be an expiring map to ensure futures that don't have | ||
103 | + // a future eventually get garbage collected. | ||
100 | private final Map<Long, InstallationFuture> pendingFutures = | 104 | private final Map<Long, InstallationFuture> pendingFutures = |
101 | new ConcurrentHashMap<Long, InstallationFuture>(); | 105 | new ConcurrentHashMap<Long, InstallationFuture>(); |
102 | 106 | ||
... | @@ -169,7 +173,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -169,7 +173,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
169 | } | 173 | } |
170 | 174 | ||
171 | @Override | 175 | @Override |
172 | - public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) { | 176 | + public ListenableFuture<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) { |
173 | final Set<Dpid> sws = | 177 | final Set<Dpid> sws = |
174 | Collections.newSetFromMap(new ConcurrentHashMap<Dpid, Boolean>()); | 178 | Collections.newSetFromMap(new ConcurrentHashMap<Dpid, Boolean>()); |
175 | final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<Long, FlowRuleBatchEntry>(); | 179 | final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<Long, FlowRuleBatchEntry>(); |
... | @@ -330,18 +334,20 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -330,18 +334,20 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
330 | 334 | ||
331 | } | 335 | } |
332 | 336 | ||
333 | - private class InstallationFuture implements Future<CompletedBatchOperation> { | 337 | + private class InstallationFuture implements ListenableFuture<CompletedBatchOperation> { |
334 | 338 | ||
335 | private final Set<Dpid> sws; | 339 | private final Set<Dpid> sws; |
336 | private final AtomicBoolean ok = new AtomicBoolean(true); | 340 | private final AtomicBoolean ok = new AtomicBoolean(true); |
337 | private final Map<Long, FlowRuleBatchEntry> fms; | 341 | private final Map<Long, FlowRuleBatchEntry> fms; |
338 | 342 | ||
339 | - private final List<FlowEntry> offendingFlowMods = Lists.newLinkedList(); | 343 | + private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet(); |
340 | 344 | ||
341 | private final CountDownLatch countDownLatch; | 345 | private final CountDownLatch countDownLatch; |
342 | private Long pendingXid; | 346 | private Long pendingXid; |
343 | private BatchState state; | 347 | private BatchState state; |
344 | 348 | ||
349 | + private final ExecutionList executionList = new ExecutionList(); | ||
350 | + | ||
345 | public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) { | 351 | public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) { |
346 | this.state = BatchState.STARTED; | 352 | this.state = BatchState.STARTED; |
347 | this.sws = sws; | 353 | this.sws = sws; |
... | @@ -350,6 +356,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -350,6 +356,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
350 | } | 356 | } |
351 | 357 | ||
352 | public void fail(OFErrorMsg msg, Dpid dpid) { | 358 | public void fail(OFErrorMsg msg, Dpid dpid) { |
359 | + | ||
353 | ok.set(false); | 360 | ok.set(false); |
354 | removeRequirement(dpid); | 361 | removeRequirement(dpid); |
355 | FlowEntry fe = null; | 362 | FlowEntry fe = null; |
... | @@ -422,6 +429,9 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -422,6 +429,9 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
422 | 429 | ||
423 | @Override | 430 | @Override |
424 | public boolean cancel(boolean mayInterruptIfRunning) { | 431 | public boolean cancel(boolean mayInterruptIfRunning) { |
432 | + if (isDone()) { | ||
433 | + return false; | ||
434 | + } | ||
425 | ok.set(false); | 435 | ok.set(false); |
426 | this.state = BatchState.CANCELLED; | 436 | this.state = BatchState.CANCELLED; |
427 | cleanUp(); | 437 | cleanUp(); |
... | @@ -434,7 +444,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -434,7 +444,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
434 | } | 444 | } |
435 | 445 | ||
436 | } | 446 | } |
437 | - return isCancelled(); | 447 | + invokeCallbacks(); |
448 | + return true; | ||
438 | } | 449 | } |
439 | 450 | ||
440 | @Override | 451 | @Override |
... | @@ -444,14 +455,15 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -444,14 +455,15 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
444 | 455 | ||
445 | @Override | 456 | @Override |
446 | public boolean isDone() { | 457 | public boolean isDone() { |
447 | - return this.state == BatchState.FINISHED; | 458 | + return this.state == BatchState.FINISHED || isCancelled(); |
448 | } | 459 | } |
449 | 460 | ||
450 | @Override | 461 | @Override |
451 | public CompletedBatchOperation get() throws InterruptedException, ExecutionException { | 462 | public CompletedBatchOperation get() throws InterruptedException, ExecutionException { |
452 | countDownLatch.await(); | 463 | countDownLatch.await(); |
453 | this.state = BatchState.FINISHED; | 464 | this.state = BatchState.FINISHED; |
454 | - return new CompletedBatchOperation(ok.get(), offendingFlowMods); | 465 | + CompletedBatchOperation result = new CompletedBatchOperation(ok.get(), offendingFlowMods); |
466 | + return result; | ||
455 | } | 467 | } |
456 | 468 | ||
457 | @Override | 469 | @Override |
... | @@ -460,7 +472,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -460,7 +472,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
460 | TimeoutException { | 472 | TimeoutException { |
461 | if (countDownLatch.await(timeout, unit)) { | 473 | if (countDownLatch.await(timeout, unit)) { |
462 | this.state = BatchState.FINISHED; | 474 | this.state = BatchState.FINISHED; |
463 | - return new CompletedBatchOperation(ok.get(), offendingFlowMods); | 475 | + CompletedBatchOperation result = new CompletedBatchOperation(ok.get(), offendingFlowMods); |
476 | + return result; | ||
464 | } | 477 | } |
465 | throw new TimeoutException(); | 478 | throw new TimeoutException(); |
466 | } | 479 | } |
... | @@ -478,10 +491,21 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -478,10 +491,21 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
478 | 491 | ||
479 | private void removeRequirement(Dpid dpid) { | 492 | private void removeRequirement(Dpid dpid) { |
480 | countDownLatch.countDown(); | 493 | countDownLatch.countDown(); |
494 | + if (countDownLatch.getCount() == 0) { | ||
495 | + invokeCallbacks(); | ||
496 | + } | ||
481 | sws.remove(dpid); | 497 | sws.remove(dpid); |
482 | cleanUp(); | 498 | cleanUp(); |
483 | } | 499 | } |
484 | 500 | ||
501 | + @Override | ||
502 | + public void addListener(Runnable runnable, Executor executor) { | ||
503 | + executionList.add(runnable, executor); | ||
504 | + } | ||
505 | + | ||
506 | + private void invokeCallbacks() { | ||
507 | + executionList.execute(); | ||
508 | + } | ||
485 | } | 509 | } |
486 | 510 | ||
487 | } | 511 | } | ... | ... |
... | @@ -6,5 +6,4 @@ | ... | @@ -6,5 +6,4 @@ |
6 | [ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1 | 6 | [ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1 |
7 | . $ONOS_ROOT/tools/build/envDefaults | 7 | . $ONOS_ROOT/tools/build/envDefaults |
8 | 8 | ||
9 | -cd $ONOS_ROOT | 9 | +cd $ONOS_ROOT && mvn clean install && cd docs && mvn javadoc:aggregate |
10 | -mvn clean install && mvn javadoc:aggregate | ... | ... |
1 | +package org.onlab.metrics; | ||
2 | + | ||
3 | +import com.codahale.metrics.Gauge; | ||
4 | +import com.codahale.metrics.Meter; | ||
5 | + | ||
6 | +/** | ||
7 | + * Metric measurements for events. | ||
8 | + */ | ||
9 | +public class EventMetric { | ||
10 | + private static final String GAUGE_TIMESTAMP_NAME = "Timestamp.EpochMs"; | ||
11 | + private static final String METER_RATE_NAME = "Rate"; | ||
12 | + | ||
13 | + private final MetricsService metricsService; | ||
14 | + private final String componentName; | ||
15 | + private final String featureName; | ||
16 | + | ||
17 | + private MetricsComponent metricsComponent; | ||
18 | + private MetricsFeature metricsFeature; | ||
19 | + | ||
20 | + private volatile long lastEventTimestampEpochMs = 0; | ||
21 | + private Gauge<Long> lastEventTimestampGauge; | ||
22 | + private Meter eventRateMeter; | ||
23 | + | ||
24 | + /** | ||
25 | + * Constructor. | ||
26 | + * | ||
27 | + * @param metricsService the Metrics Service to use for Metrics | ||
28 | + * registration and deregistration | ||
29 | + * @param componentName the Metrics Component Name to use for Metrics | ||
30 | + * registration and deregistration | ||
31 | + * @param featureName the Metrics Feature Name to use for Metrics | ||
32 | + * registration and deregistration | ||
33 | + */ | ||
34 | + public EventMetric(MetricsService metricsService, String componentName, | ||
35 | + String featureName) { | ||
36 | + this.metricsService = metricsService; | ||
37 | + this.componentName = componentName; | ||
38 | + this.featureName = featureName; | ||
39 | + } | ||
40 | + | ||
41 | + /** | ||
42 | + * Registers the metrics. | ||
43 | + */ | ||
44 | + public void registerMetrics() { | ||
45 | + metricsComponent = metricsService.registerComponent(componentName); | ||
46 | + metricsFeature = metricsComponent.registerFeature(featureName); | ||
47 | + | ||
48 | + lastEventTimestampEpochMs = 0; | ||
49 | + lastEventTimestampGauge = | ||
50 | + metricsService.registerMetric(metricsComponent, | ||
51 | + metricsFeature, | ||
52 | + GAUGE_TIMESTAMP_NAME, | ||
53 | + new Gauge<Long>() { | ||
54 | + @Override | ||
55 | + public Long getValue() { | ||
56 | + return lastEventTimestampEpochMs; | ||
57 | + } | ||
58 | + }); | ||
59 | + | ||
60 | + eventRateMeter = metricsService.createMeter(metricsComponent, | ||
61 | + metricsFeature, | ||
62 | + METER_RATE_NAME); | ||
63 | + } | ||
64 | + | ||
65 | + /** | ||
66 | + * Removes the metrics. | ||
67 | + */ | ||
68 | + public void removeMetrics() { | ||
69 | + lastEventTimestampEpochMs = 0; | ||
70 | + metricsService.removeMetric(metricsComponent, | ||
71 | + metricsFeature, | ||
72 | + GAUGE_TIMESTAMP_NAME); | ||
73 | + metricsService.removeMetric(metricsComponent, | ||
74 | + metricsFeature, | ||
75 | + METER_RATE_NAME); | ||
76 | + } | ||
77 | + | ||
78 | + /** | ||
79 | + * Updates the metric measurements for a single event. | ||
80 | + */ | ||
81 | + public void eventReceived() { | ||
82 | + lastEventTimestampEpochMs = System.currentTimeMillis(); | ||
83 | + eventRateMeter.mark(1); | ||
84 | + } | ||
85 | + | ||
86 | + /** | ||
87 | + * Gets the last event timestamp Gauge (ms from the Epoch). | ||
88 | + * | ||
89 | + * @return the last event timestamp Gauge (ms from the Epoch) | ||
90 | + */ | ||
91 | + public Gauge<Long> lastEventTimestampGauge() { | ||
92 | + return lastEventTimestampGauge; | ||
93 | + } | ||
94 | + | ||
95 | + /** | ||
96 | + * Gets the event rate meter. | ||
97 | + * | ||
98 | + * @return the event rate meter | ||
99 | + */ | ||
100 | + public Meter eventRateMeter() { | ||
101 | + return eventRateMeter; | ||
102 | + } | ||
103 | +} |
... | @@ -32,7 +32,7 @@ public final class ChassisId { | ... | @@ -32,7 +32,7 @@ public final class ChassisId { |
32 | * @param value the value to use. | 32 | * @param value the value to use. |
33 | */ | 33 | */ |
34 | public ChassisId(String value) { | 34 | public ChassisId(String value) { |
35 | - this.value = Long.valueOf(value, 16); | 35 | + this.value = Long.parseLong(value, 16); |
36 | } | 36 | } |
37 | 37 | ||
38 | /** | 38 | /** | ... | ... |
... | @@ -379,7 +379,7 @@ public class DHCP extends BasePacket { | ... | @@ -379,7 +379,7 @@ public class DHCP extends BasePacket { |
379 | // 300 | 379 | // 300 |
380 | int optionsLength = 0; | 380 | int optionsLength = 0; |
381 | for (final DHCPOption option : this.options) { | 381 | for (final DHCPOption option : this.options) { |
382 | - if (option.getCode() == 0 || option.getCode() == 255) { | 382 | + if (option.getCode() == 0 || option.getCode() == ((byte) 255)) { |
383 | optionsLength += 1; | 383 | optionsLength += 1; |
384 | } else { | 384 | } else { |
385 | optionsLength += 2 + (0xff & option.getLength()); | 385 | optionsLength += 2 + (0xff & option.getLength()); | ... | ... |
... | @@ -438,7 +438,7 @@ public class IPv4 extends BasePacket { | ... | @@ -438,7 +438,7 @@ public class IPv4 extends BasePacket { |
438 | 438 | ||
439 | int result = 0; | 439 | int result = 0; |
440 | for (int i = 0; i < 4; ++i) { | 440 | for (int i = 0; i < 4; ++i) { |
441 | - result |= Integer.valueOf(octets[i]) << (3 - i) * 8; | 441 | + result |= Integer.parseInt(octets[i]) << (3 - i) * 8; |
442 | } | 442 | } |
443 | return result; | 443 | return result; |
444 | } | 444 | } |
... | @@ -471,7 +471,7 @@ public class IPv4 extends BasePacket { | ... | @@ -471,7 +471,7 @@ public class IPv4 extends BasePacket { |
471 | int result = 0; | 471 | int result = 0; |
472 | for (int i = 0; i < 4; ++i) { | 472 | for (int i = 0; i < 4; ++i) { |
473 | result = ipAddress >> (3 - i) * 8 & 0xff; | 473 | result = ipAddress >> (3 - i) * 8 & 0xff; |
474 | - sb.append(Integer.valueOf(result).toString()); | 474 | + sb.append(result); |
475 | if (i != 3) { | 475 | if (i != 3) { |
476 | sb.append("."); | 476 | sb.append("."); |
477 | } | 477 | } | ... | ... |
... | @@ -14,7 +14,7 @@ public final class HexString { | ... | @@ -14,7 +14,7 @@ public final class HexString { |
14 | */ | 14 | */ |
15 | public static String toHexString(final byte[] bytes) { | 15 | public static String toHexString(final byte[] bytes) { |
16 | int i; | 16 | int i; |
17 | - StringBuilder ret = new StringBuilder(); | 17 | + StringBuilder ret = new StringBuilder(bytes.length * 3 - 1); |
18 | String tmp; | 18 | String tmp; |
19 | for (i = 0; i < bytes.length; i++) { | 19 | for (i = 0; i < bytes.length; i++) { |
20 | if (i > 0) { | 20 | if (i > 0) { |
... | @@ -31,22 +31,22 @@ public final class HexString { | ... | @@ -31,22 +31,22 @@ public final class HexString { |
31 | 31 | ||
32 | public static String toHexString(final long val, final int padTo) { | 32 | public static String toHexString(final long val, final int padTo) { |
33 | char[] arr = Long.toHexString(val).toCharArray(); | 33 | char[] arr = Long.toHexString(val).toCharArray(); |
34 | - String ret = ""; | 34 | + StringBuilder ret = new StringBuilder(padTo * 3 - 1); |
35 | // prepend the right number of leading zeros | 35 | // prepend the right number of leading zeros |
36 | int i = 0; | 36 | int i = 0; |
37 | for (; i < (padTo * 2 - arr.length); i++) { | 37 | for (; i < (padTo * 2 - arr.length); i++) { |
38 | - ret += "0"; | 38 | + ret.append('0'); |
39 | if ((i % 2) != 0) { | 39 | if ((i % 2) != 0) { |
40 | - ret += ":"; | 40 | + ret.append(':'); |
41 | } | 41 | } |
42 | } | 42 | } |
43 | for (int j = 0; j < arr.length; j++) { | 43 | for (int j = 0; j < arr.length; j++) { |
44 | - ret += arr[j]; | 44 | + ret.append(arr[j]); |
45 | if ((((i + j) % 2) != 0) && (j < (arr.length - 1))) { | 45 | if ((((i + j) % 2) != 0) && (j < (arr.length - 1))) { |
46 | - ret += ":"; | 46 | + ret.append(':'); |
47 | } | 47 | } |
48 | } | 48 | } |
49 | - return ret; | 49 | + return ret.toString(); |
50 | } | 50 | } |
51 | 51 | ||
52 | public static String toHexString(final long val) { | 52 | public static String toHexString(final long val) { | ... | ... |
... | @@ -163,6 +163,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -163,6 +163,7 @@ public class NettyMessagingService implements MessagingService { |
163 | handlers.putIfAbsent(type, handler); | 163 | handlers.putIfAbsent(type, handler); |
164 | } | 164 | } |
165 | 165 | ||
166 | + @Override | ||
166 | public void unregisterHandler(String type) { | 167 | public void unregisterHandler(String type) { |
167 | handlers.remove(type); | 168 | handlers.remove(type); |
168 | } | 169 | } |
... | @@ -242,7 +243,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -242,7 +243,7 @@ public class NettyMessagingService implements MessagingService { |
242 | } | 243 | } |
243 | } | 244 | } |
244 | 245 | ||
245 | - private class WriteTask implements Runnable { | 246 | + private static class WriteTask implements Runnable { |
246 | 247 | ||
247 | private final InternalMessage message; | 248 | private final InternalMessage message; |
248 | private final Channel channel; | 249 | private final Channel channel; | ... | ... |
web/gui/src/main/webapp/img/device.png
0 → 100644

9.27 KB
web/gui/src/main/webapp/img/host.png
0 → 100644

9.83 KB
web/gui/src/main/webapp/img/onos-logo.png
0 → 100644

16.9 KB
... | @@ -15,19 +15,18 @@ | ... | @@ -15,19 +15,18 @@ |
15 | <link rel="stylesheet" href="onos.css"> | 15 | <link rel="stylesheet" href="onos.css"> |
16 | 16 | ||
17 | <script src="geometry.js"></script> | 17 | <script src="geometry.js"></script> |
18 | - <script src="onosui.js"></script> | 18 | + <script src="onos.js"></script> |
19 | 19 | ||
20 | </head> | 20 | </head> |
21 | <body> | 21 | <body> |
22 | <div id="frame"> | 22 | <div id="frame"> |
23 | <div id="mast"> | 23 | <div id="mast"> |
24 | - <span class="title"> | 24 | + <img id="logo" src="img/onos-logo.png" width="60" height="38"> |
25 | - ONOS Web UI | 25 | + <span class="title">Open Network Operating System</span> |
26 | - </span> | ||
27 | <span class="right"> | 26 | <span class="right"> |
28 | - <span class="radio">[one]</span> | 27 | + <span class="radio">[All Layers]</span> |
29 | - <span class="radio">[two]</span> | 28 | + <span class="radio">[Packet Only]</span> |
30 | - <span class="radio">[three]</span> | 29 | + <span class="radio">[Optical Only]</span> |
31 | </span> | 30 | </span> |
32 | </div> | 31 | </div> |
33 | <div id="view"></div> | 32 | <div id="view"></div> | ... | ... |
... | @@ -10,17 +10,32 @@ | ... | @@ -10,17 +10,32 @@ |
10 | var api = onos.api; | 10 | var api = onos.api; |
11 | 11 | ||
12 | var config = { | 12 | var config = { |
13 | - layering: false, | 13 | + options: { |
14 | + layering: true, | ||
15 | + collisionPrevention: true | ||
16 | + }, | ||
14 | jsonUrl: 'network.json', | 17 | jsonUrl: 'network.json', |
15 | iconUrl: { | 18 | iconUrl: { |
16 | - pkt: 'pkt.png', | 19 | + device: 'img/device.png', |
17 | - opt: 'opt.png' | 20 | + host: 'img/host.png', |
21 | + pkt: 'img/pkt.png', | ||
22 | + opt: 'img/opt.png' | ||
18 | }, | 23 | }, |
19 | - mastHeight: 32, | 24 | + mastHeight: 36, |
20 | force: { | 25 | force: { |
21 | - linkDistance: 240, | 26 | + note: 'node.class or link.class is used to differentiate', |
22 | - linkStrength: 0.8, | 27 | + linkDistance: { |
23 | - charge: -400, | 28 | + infra: 240, |
29 | + host: 100 | ||
30 | + }, | ||
31 | + linkStrength: { | ||
32 | + infra: 1.0, | ||
33 | + host: 0.4 | ||
34 | + }, | ||
35 | + charge: { | ||
36 | + device: -800, | ||
37 | + host: -400 | ||
38 | + }, | ||
24 | ticksWithoutCollisions: 50, | 39 | ticksWithoutCollisions: 50, |
25 | marginLR: 20, | 40 | marginLR: 20, |
26 | marginTB: 20, | 41 | marginTB: 20, |
... | @@ -31,19 +46,28 @@ | ... | @@ -31,19 +46,28 @@ |
31 | } | 46 | } |
32 | }, | 47 | }, |
33 | labels: { | 48 | labels: { |
34 | - imgPad: 22, | 49 | + imgPad: 16, |
35 | padLR: 8, | 50 | padLR: 8, |
36 | padTB: 6, | 51 | padTB: 6, |
37 | marginLR: 3, | 52 | marginLR: 3, |
38 | marginTB: 2 | 53 | marginTB: 2 |
39 | }, | 54 | }, |
55 | + icons: { | ||
56 | + w: 32, | ||
57 | + h: 32, | ||
58 | + xoff: -12, | ||
59 | + yoff: -8 | ||
60 | + }, | ||
40 | constraints: { | 61 | constraints: { |
41 | ypos: { | 62 | ypos: { |
42 | - pkt: 0.3, | 63 | + host: 0.15, |
43 | - opt: 0.7 | 64 | + switch: 0.3, |
44 | - } | 65 | + roadm: 0.7 |
45 | } | 66 | } |
46 | }, | 67 | }, |
68 | + hostLinkWidth: 1.0, | ||
69 | + mouseOutTimerDelayMs: 120 | ||
70 | + }, | ||
47 | view = {}, | 71 | view = {}, |
48 | network = {}, | 72 | network = {}, |
49 | selected = {}, | 73 | selected = {}, |
... | @@ -104,14 +128,23 @@ | ... | @@ -104,14 +128,23 @@ |
104 | var nw = network.forceWidth, | 128 | var nw = network.forceWidth, |
105 | nh = network.forceHeight; | 129 | nh = network.forceHeight; |
106 | 130 | ||
107 | - network.data.nodes.forEach(function(n) { | 131 | + function yPosConstraintForNode(n) { |
132 | + return config.constraints.ypos[n.type || 'host']; | ||
133 | + } | ||
134 | + | ||
135 | + // Note that both 'devices' and 'hosts' get mapped into the nodes array | ||
136 | + | ||
137 | + // first, the devices... | ||
138 | + network.data.devices.forEach(function(n) { | ||
108 | var ypc = yPosConstraintForNode(n), | 139 | var ypc = yPosConstraintForNode(n), |
109 | ix = Math.random() * 0.6 * nw + 0.2 * nw, | 140 | ix = Math.random() * 0.6 * nw + 0.2 * nw, |
110 | iy = ypc * nh, | 141 | iy = ypc * nh, |
111 | node = { | 142 | node = { |
112 | id: n.id, | 143 | id: n.id, |
144 | + labels: n.labels, | ||
145 | + class: 'device', | ||
146 | + icon: 'device', | ||
113 | type: n.type, | 147 | type: n.type, |
114 | - status: n.status, | ||
115 | x: ix, | 148 | x: ix, |
116 | y: iy, | 149 | y: iy, |
117 | constraint: { | 150 | constraint: { |
... | @@ -123,21 +156,61 @@ | ... | @@ -123,21 +156,61 @@ |
123 | network.nodes.push(node); | 156 | network.nodes.push(node); |
124 | }); | 157 | }); |
125 | 158 | ||
126 | - function yPosConstraintForNode(n) { | 159 | + // then, the hosts... |
127 | - return config.constraints.ypos[n.type] || 0.5; | 160 | + network.data.hosts.forEach(function(n) { |
161 | + var ypc = yPosConstraintForNode(n), | ||
162 | + ix = Math.random() * 0.6 * nw + 0.2 * nw, | ||
163 | + iy = ypc * nh, | ||
164 | + node = { | ||
165 | + id: n.id, | ||
166 | + labels: n.labels, | ||
167 | + class: 'host', | ||
168 | + icon: 'host', | ||
169 | + type: n.type, | ||
170 | + x: ix, | ||
171 | + y: iy, | ||
172 | + constraint: { | ||
173 | + weight: 0.7, | ||
174 | + y: iy | ||
128 | } | 175 | } |
176 | + }; | ||
177 | + network.lookup[n.id] = node; | ||
178 | + network.nodes.push(node); | ||
179 | + }); | ||
129 | 180 | ||
130 | 181 | ||
182 | + // now, process the explicit links... | ||
131 | network.data.links.forEach(function(n) { | 183 | network.data.links.forEach(function(n) { |
132 | var src = network.lookup[n.src], | 184 | var src = network.lookup[n.src], |
133 | dst = network.lookup[n.dst], | 185 | dst = network.lookup[n.dst], |
134 | id = src.id + "~" + dst.id; | 186 | id = src.id + "~" + dst.id; |
135 | 187 | ||
136 | var link = { | 188 | var link = { |
189 | + class: 'infra', | ||
190 | + id: id, | ||
191 | + type: n.type, | ||
192 | + width: n.linkWidth, | ||
193 | + source: src, | ||
194 | + target: dst, | ||
195 | + strength: config.force.linkStrength.infra | ||
196 | + }; | ||
197 | + network.links.push(link); | ||
198 | + }); | ||
199 | + | ||
200 | + // finally, infer host links... | ||
201 | + network.data.hosts.forEach(function(n) { | ||
202 | + var src = network.lookup[n.id], | ||
203 | + dst = network.lookup[n.cp.device], | ||
204 | + id = src.id + "~" + dst.id; | ||
205 | + | ||
206 | + var link = { | ||
207 | + class: 'host', | ||
137 | id: id, | 208 | id: id, |
209 | + type: 'hostLink', | ||
210 | + width: config.hostLinkWidth, | ||
138 | source: src, | 211 | source: src, |
139 | target: dst, | 212 | target: dst, |
140 | - strength: config.force.linkStrength | 213 | + strength: config.force.linkStrength.host |
141 | }; | 214 | }; |
142 | network.links.push(link); | 215 | network.links.push(link); |
143 | }); | 216 | }); |
... | @@ -145,13 +218,15 @@ | ... | @@ -145,13 +218,15 @@ |
145 | 218 | ||
146 | function createLayout() { | 219 | function createLayout() { |
147 | 220 | ||
221 | + var cfg = config.force; | ||
222 | + | ||
148 | network.force = d3.layout.force() | 223 | network.force = d3.layout.force() |
224 | + .size([network.forceWidth, network.forceHeight]) | ||
149 | .nodes(network.nodes) | 225 | .nodes(network.nodes) |
150 | .links(network.links) | 226 | .links(network.links) |
151 | - .linkStrength(function(d) { return d.strength; }) | 227 | + .linkStrength(function(d) { return cfg.linkStrength[d.class]; }) |
152 | - .size([network.forceWidth, network.forceHeight]) | 228 | + .linkDistance(function(d) { return cfg.linkDistance[d.class]; }) |
153 | - .linkDistance(config.force.linkDistance) | 229 | + .charge(function(d) { return cfg.charge[d.class]; }) |
154 | - .charge(config.force.charge) | ||
155 | .on('tick', tick); | 230 | .on('tick', tick); |
156 | 231 | ||
157 | network.svg = d3.select('#view').append('svg') | 232 | network.svg = d3.select('#view').append('svg') |
... | @@ -205,9 +280,10 @@ | ... | @@ -205,9 +280,10 @@ |
205 | network.link = network.svg.append('g').selectAll('.link') | 280 | network.link = network.svg.append('g').selectAll('.link') |
206 | .data(network.force.links(), function(d) {return d.id}) | 281 | .data(network.force.links(), function(d) {return d.id}) |
207 | .enter().append('line') | 282 | .enter().append('line') |
208 | - .attr('class', 'link'); | 283 | + .attr('class', function(d) {return 'link ' + d.class}); |
284 | + | ||
209 | 285 | ||
210 | - // TODO: drag behavior | 286 | + // == define node drag behavior... |
211 | network.draggedThreshold = d3.scale.linear() | 287 | network.draggedThreshold = d3.scale.linear() |
212 | .domain([0, 0.1]) | 288 | .domain([0, 0.1]) |
213 | .range([5, 20]) | 289 | .range([5, 20]) |
... | @@ -258,7 +334,11 @@ | ... | @@ -258,7 +334,11 @@ |
258 | .data(network.force.nodes(), function(d) {return d.id}) | 334 | .data(network.force.nodes(), function(d) {return d.id}) |
259 | .enter().append('g') | 335 | .enter().append('g') |
260 | .attr('class', function(d) { | 336 | .attr('class', function(d) { |
261 | - return 'node ' + d.type; | 337 | + var cls = 'node ' + d.class; |
338 | + if (d.type) { | ||
339 | + cls += ' ' + d.type; | ||
340 | + } | ||
341 | + return cls; | ||
262 | }) | 342 | }) |
263 | .attr('transform', function(d) { | 343 | .attr('transform', function(d) { |
264 | return translate(d.x, d.y); | 344 | return translate(d.x, d.y); |
... | @@ -281,29 +361,33 @@ | ... | @@ -281,29 +361,33 @@ |
281 | } | 361 | } |
282 | network.mouseoutTimeout = setTimeout(function() { | 362 | network.mouseoutTimeout = setTimeout(function() { |
283 | highlightObject(null); | 363 | highlightObject(null); |
284 | - }, 160); | 364 | + }, config.mouseOutTimerDelayMs); |
285 | } | 365 | } |
286 | }); | 366 | }); |
287 | 367 | ||
288 | network.nodeRect = network.node.append('rect') | 368 | network.nodeRect = network.node.append('rect') |
289 | .attr('rx', 5) | 369 | .attr('rx', 5) |
290 | - .attr('ry', 5) | 370 | + .attr('ry', 5); |
291 | - .attr('width', 126) | 371 | + // note that width/height are adjusted to fit the label text |
292 | - .attr('height', 40); | ||
293 | 372 | ||
294 | network.node.each(function(d) { | 373 | network.node.each(function(d) { |
295 | var node = d3.select(this), | 374 | var node = d3.select(this), |
296 | rect = node.select('rect'), | 375 | rect = node.select('rect'), |
297 | - img = node.append('svg:image') | 376 | + icon = iconUrl(d), |
298 | - .attr('x', -16) | ||
299 | - .attr('y', -16) | ||
300 | - .attr('width', 32) | ||
301 | - .attr('height', 32) | ||
302 | - .attr('xlink:href', iconUrl(d)), | ||
303 | text = node.append('text') | 377 | text = node.append('text') |
378 | + // TODO: add label cycle behavior | ||
304 | .text(d.id) | 379 | .text(d.id) |
305 | - .attr('dy', '1.1em'), | 380 | + .attr('dy', '1.1em'); |
306 | - dummy; | 381 | + |
382 | + if (icon) { | ||
383 | + var cfg = config.icons; | ||
384 | + node.append('svg:image') | ||
385 | + .attr('width', cfg.w) | ||
386 | + .attr('height', cfg.h) | ||
387 | + .attr('xlink:href', icon); | ||
388 | + // note, icon relative positioning (x,y) is done after we have | ||
389 | + // adjusted the bounds of the rectangle... | ||
390 | + } | ||
307 | 391 | ||
308 | }); | 392 | }); |
309 | 393 | ||
... | @@ -352,7 +436,8 @@ | ... | @@ -352,7 +436,8 @@ |
352 | .attr('height', bounds.y2 - bounds.y1); | 436 | .attr('height', bounds.y2 - bounds.y1); |
353 | 437 | ||
354 | node.select('image') | 438 | node.select('image') |
355 | - .attr('x', bounds.x1); | 439 | + .attr('x', bounds.x1 + config.icons.xoff) |
440 | + .attr('y', bounds.y1 + config.icons.yoff); | ||
356 | 441 | ||
357 | d.extent = { | 442 | d.extent = { |
358 | left: bounds.x1 - lab.marginLR, | 443 | left: bounds.x1 - lab.marginLR, |
... | @@ -384,7 +469,7 @@ | ... | @@ -384,7 +469,7 @@ |
384 | } | 469 | } |
385 | 470 | ||
386 | function iconUrl(d) { | 471 | function iconUrl(d) { |
387 | - return config.iconUrl[d.type]; | 472 | + return config.iconUrl[d.icon]; |
388 | } | 473 | } |
389 | 474 | ||
390 | function translate(x, y) { | 475 | function translate(x, y) { |
... | @@ -440,7 +525,7 @@ | ... | @@ -440,7 +525,7 @@ |
440 | function tick(e) { | 525 | function tick(e) { |
441 | network.numTicks++; | 526 | network.numTicks++; |
442 | 527 | ||
443 | - if (config.layering) { | 528 | + if (config.options.layering) { |
444 | // adjust the y-coord of each node, based on y-pos constraints | 529 | // adjust the y-coord of each node, based on y-pos constraints |
445 | network.nodes.forEach(function (n) { | 530 | network.nodes.forEach(function (n) { |
446 | var z = e.alpha * n.constraint.weight; | 531 | var z = e.alpha * n.constraint.weight; |
... | @@ -450,7 +535,7 @@ | ... | @@ -450,7 +535,7 @@ |
450 | }); | 535 | }); |
451 | } | 536 | } |
452 | 537 | ||
453 | - if (network.preventCollisions) { | 538 | + if (config.options.collisionPrevention && network.preventCollisions) { |
454 | preventCollisions(); | 539 | preventCollisions(); |
455 | } | 540 | } |
456 | 541 | ... | ... |
1 | { | 1 | { |
2 | - "id": "network-v1", | ||
3 | "meta": { | 2 | "meta": { |
4 | - "__comment_1__": "This is sample data for developing the ONOS UI", | 3 | + "comments": [ |
5 | - "foo": "bar", | 4 | + "This is sample data for developing the ONOS UI (network view)", |
6 | - "zoo": "goo" | 5 | + " in a standalone mode (no server required).", |
6 | + " Eventually, we will wire this up to live data", | ||
7 | + " from the server, via a websocket.", | ||
8 | + "", | ||
9 | + "Note that this is just a first-draft of the data --", | ||
10 | + " additional fields will be added when they are needed." | ||
11 | + ], | ||
12 | + "otherMetaData": "can go here..." | ||
7 | }, | 13 | }, |
8 | - "nodes": [ | 14 | + "devices": [ |
9 | { | 15 | { |
10 | - "id": "sample1", | 16 | + "id": "of:0000000000000001", |
11 | - "type": "opt", | 17 | + "labels": ["00:00:00:00:00:00:00:01", "of/::01", "opt-1"], |
12 | - "status": "good" | 18 | + "type": "roadm" |
13 | }, | 19 | }, |
14 | { | 20 | { |
15 | - "id": "00:00:00:00:00:00:00:02", | 21 | + "id": "of:0000000000000002", |
16 | - "type": "opt", | 22 | + "labels": ["00:00:00:00:00:00:00:02", "of/::02", "opt-2"], |
17 | - "status": "good" | 23 | + "type": "roadm" |
18 | }, | 24 | }, |
19 | { | 25 | { |
20 | - "id": "00:00:00:00:00:00:00:03", | 26 | + "id": "of:0000000000000003", |
21 | - "type": "opt", | 27 | + "labels": ["00:00:00:00:00:00:00:03", "of/::03", "opt-3"], |
22 | - "status": "good" | 28 | + "type": "roadm" |
23 | }, | 29 | }, |
24 | { | 30 | { |
25 | - "id": "00:00:00:00:00:00:00:04", | 31 | + "id": "of:0000000000000004", |
26 | - "type": "opt", | 32 | + "labels": ["00:00:00:00:00:00:00:04", "of/::04", "opt-4"], |
27 | - "status": "good" | 33 | + "type": "roadm" |
28 | }, | 34 | }, |
29 | { | 35 | { |
30 | - "id": "00:00:00:00:00:00:00:11", | 36 | + "id": "of:0000000000000011", |
31 | - "type": "pkt", | 37 | + "labels": ["00:00:00:00:00:00:00:11", "of/::11", "pkt-11"], |
32 | - "status": "good" | 38 | + "type": "switch" |
33 | }, | 39 | }, |
34 | { | 40 | { |
35 | - "id": "00:00:00:00:00:00:00:12", | 41 | + "id": "of:0000000000000012", |
36 | - "type": "pkt", | 42 | + "labels": ["00:00:00:00:00:00:00:12", "of/::12", "pkt-12"], |
37 | - "status": "good" | 43 | + "type": "switch" |
38 | }, | 44 | }, |
39 | { | 45 | { |
40 | - "id": "00:00:00:00:00:00:00:13", | 46 | + "id": "of:0000000000000013", |
41 | - "type": "pkt", | 47 | + "labels": ["00:00:00:00:00:00:00:13", "of/::13", "pkt-13"], |
42 | - "status": "good" | 48 | + "type": "switch" |
43 | } | 49 | } |
44 | ], | 50 | ], |
51 | + "linkNotes": [ | ||
52 | + "even though we have 'directionality' (src/dst), each link is", | ||
53 | + " considered to be bi-directional. Note that links between hosts", | ||
54 | + " and edge switches are inferred from host information, and not", | ||
55 | + " explicitly represented here." | ||
56 | + ], | ||
45 | "links": [ | 57 | "links": [ |
46 | - { "src": "sample1", "dst": "00:00:00:00:00:00:00:02" }, | 58 | + { |
47 | - { "src": "sample1", "dst": "00:00:00:00:00:00:00:03" }, | 59 | + "src": "of:0000000000000001", |
48 | - { "src": "sample1", "dst": "00:00:00:00:00:00:00:04" }, | 60 | + "dst": "of:0000000000000002", |
49 | - { "src": "00:00:00:00:00:00:00:02", "dst": "00:00:00:00:00:00:00:03" }, | 61 | + "type": "optical", |
50 | - { "src": "00:00:00:00:00:00:00:02", "dst": "00:00:00:00:00:00:00:04" }, | 62 | + "linkWidth": 1.5 |
51 | - { "src": "00:00:00:00:00:00:00:03", "dst": "00:00:00:00:00:00:00:04" }, | 63 | + }, |
52 | - { "src": "00:00:00:00:00:00:00:13", "dst": "00:00:00:00:00:00:00:03" }, | 64 | + { |
53 | - { "src": "00:00:00:00:00:00:00:12", "dst": "00:00:00:00:00:00:00:02" }, | 65 | + "src": "of:0000000000000001", |
54 | - { "src": "00:00:00:00:00:00:00:11", "dst": "sample1" } | 66 | + "dst": "of:0000000000000003", |
67 | + "type": "optical", | ||
68 | + "linkWidth": 1.5 | ||
69 | + }, | ||
70 | + { | ||
71 | + "src": "of:0000000000000001", | ||
72 | + "dst": "of:0000000000000004", | ||
73 | + "type": "optical", | ||
74 | + "linkWidth": 1.5 | ||
75 | + }, | ||
76 | + { | ||
77 | + "src": "of:0000000000000002", | ||
78 | + "dst": "of:0000000000000003", | ||
79 | + "type": "optical", | ||
80 | + "linkWidth": 1.5 | ||
81 | + }, | ||
82 | + { | ||
83 | + "src": "of:0000000000000002", | ||
84 | + "dst": "of:0000000000000004", | ||
85 | + "type": "optical", | ||
86 | + "linkWidth": 1.5 | ||
87 | + }, | ||
88 | + { | ||
89 | + "src": "of:0000000000000003", | ||
90 | + "dst": "of:0000000000000004", | ||
91 | + "type": "optical", | ||
92 | + "linkWidth": 1.5 | ||
93 | + }, | ||
94 | + { | ||
95 | + "src": "of:0000000000000013", | ||
96 | + "dst": "of:0000000000000003", | ||
97 | + "type": "direct", | ||
98 | + "linkWidth": 1.0 | ||
99 | + }, | ||
100 | + { | ||
101 | + "src": "of:0000000000000012", | ||
102 | + "dst": "of:0000000000000002", | ||
103 | + "type": "direct", | ||
104 | + "linkWidth": 1.0 | ||
105 | + }, | ||
106 | + { | ||
107 | + "src": "of:0000000000000011", | ||
108 | + "dst": "of:0000000000000001", | ||
109 | + "type": "direct", | ||
110 | + "linkWidth": 1.0 | ||
111 | + } | ||
112 | + ], | ||
113 | + "hosts": [ | ||
114 | + { | ||
115 | + "id": "00:60:d3:00:11:01/7", | ||
116 | + "labels": ["00:60:d3:00:11:01/7", "Host-11-A"], | ||
117 | + "cp" : { | ||
118 | + "device": "of:0000000000000011", | ||
119 | + "port": 6 | ||
120 | + } | ||
121 | + }, | ||
122 | + { | ||
123 | + "id": "00:60:d3:00:11:02/7", | ||
124 | + "labels": ["00:60:d3:00:11:02/7", "Host-11-B"], | ||
125 | + "cp" : { | ||
126 | + "device": "of:0000000000000011", | ||
127 | + "port": 8 | ||
128 | + } | ||
129 | + }, | ||
130 | + { | ||
131 | + "id": "00:60:d3:00:12:01/4", | ||
132 | + "labels": ["00:60:d3:00:12:01/4", "Host-12-C"], | ||
133 | + "cp" : { | ||
134 | + "device": "of:0000000000000012", | ||
135 | + "port": 12 | ||
136 | + } | ||
137 | + }, | ||
138 | + { | ||
139 | + "id": "00:60:d3:00:12:02/4", | ||
140 | + "labels": ["00:60:d3:00:12:02/4", "Host-12-D"], | ||
141 | + "cp" : { | ||
142 | + "device": "of:0000000000000012", | ||
143 | + "port": 13 | ||
144 | + } | ||
145 | + }, | ||
146 | + { | ||
147 | + "id": "00:60:d3:00:13:01/19", | ||
148 | + "labels": ["00:60:d3:00:13:01/19", "Host-13-E"], | ||
149 | + "cp" : { | ||
150 | + "device": "of:0000000000000013", | ||
151 | + "port": 7 | ||
152 | + } | ||
153 | + }, | ||
154 | + { | ||
155 | + "id": "00:60:d3:00:13:02/19", | ||
156 | + "labels": ["00:60:d3:00:13:02/19", "Host-13-F"], | ||
157 | + "cp" : { | ||
158 | + "device": "of:0000000000000013", | ||
159 | + "port": 8 | ||
160 | + } | ||
161 | + } | ||
55 | ] | 162 | ] |
56 | } | 163 | } | ... | ... |
... | @@ -13,13 +13,15 @@ body, html { | ... | @@ -13,13 +13,15 @@ body, html { |
13 | */ | 13 | */ |
14 | 14 | ||
15 | span.title { | 15 | span.title { |
16 | - color: darkblue; | 16 | + color: #37b; |
17 | - font-size: 16pt; | 17 | + font-size: 14pt; |
18 | font-style: italic; | 18 | font-style: italic; |
19 | + vertical-align: 10px; | ||
19 | } | 20 | } |
20 | 21 | ||
21 | span.radio { | 22 | span.radio { |
22 | color: darkslateblue; | 23 | color: darkslateblue; |
24 | + font-size: 10pt; | ||
23 | } | 25 | } |
24 | 26 | ||
25 | span.right { | 27 | span.right { |
... | @@ -38,7 +40,7 @@ svg { | ... | @@ -38,7 +40,7 @@ svg { |
38 | * Network Graph elements ====================================== | 40 | * Network Graph elements ====================================== |
39 | */ | 41 | */ |
40 | 42 | ||
41 | -.link { | 43 | +svg .link { |
42 | fill: none; | 44 | fill: none; |
43 | stroke: #666; | 45 | stroke: #666; |
44 | stroke-width: 1.5px; | 46 | stroke-width: 1.5px; |
... | @@ -56,7 +58,7 @@ marker#end { | ... | @@ -56,7 +58,7 @@ marker#end { |
56 | stroke-width: 1.5px; | 58 | stroke-width: 1.5px; |
57 | } | 59 | } |
58 | 60 | ||
59 | -.node rect { | 61 | +svg .node rect { |
60 | stroke-width: 1.5px; | 62 | stroke-width: 1.5px; |
61 | 63 | ||
62 | transition: opacity 250ms; | 64 | transition: opacity 250ms; |
... | @@ -64,13 +66,15 @@ marker#end { | ... | @@ -64,13 +66,15 @@ marker#end { |
64 | -moz-transition: opacity 250ms; | 66 | -moz-transition: opacity 250ms; |
65 | } | 67 | } |
66 | 68 | ||
67 | -/*differentiate between packet and optical nodes*/ | 69 | +svg .node.device.roadm rect { |
68 | -svg .node.pkt rect { | 70 | + fill: #229; |
69 | - fill: #77a; | 71 | +} |
72 | +svg .node.device.switch rect { | ||
73 | + fill: #55f; | ||
70 | } | 74 | } |
71 | 75 | ||
72 | -svg .node.opt rect { | 76 | +svg .node.host rect { |
73 | - fill: #7a7; | 77 | + fill: #787; |
74 | } | 78 | } |
75 | 79 | ||
76 | svg .node text { | 80 | svg .node text { |
... | @@ -121,15 +125,13 @@ svg .legend .category text { | ... | @@ -121,15 +125,13 @@ svg .legend .category text { |
121 | #frame { | 125 | #frame { |
122 | width: 100%; | 126 | width: 100%; |
123 | height: 100%; | 127 | height: 100%; |
124 | - background-color: #cdf; | 128 | + background-color: #fff; |
125 | } | 129 | } |
126 | 130 | ||
127 | #mast { | 131 | #mast { |
128 | - height: 32px; | 132 | + height: 36px; |
129 | - background-color: #abe; | 133 | + padding: 4px; |
134 | + background-color: #ccc; | ||
130 | vertical-align: baseline; | 135 | vertical-align: baseline; |
131 | } | 136 | } |
132 | 137 | ||
133 | -#main { | ||
134 | - background-color: #99c; | ||
135 | -} | ... | ... |
-
Please register or login to post a comment