blob: 25d6a50e30f1ecd1f3a1a5ea434597b89c7fca2a [file] [log] [blame]
Carmelo Casconefa421582018-09-13 10:05:57 -07001/*
2 * Copyright 2015-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.inbandtelemetry.impl;
17
18import com.google.common.collect.Maps;
19import com.google.common.util.concurrent.Striped;
Carmelo Casconefa421582018-09-13 10:05:57 -070020import org.onlab.util.KryoNamespace;
21import org.onlab.util.SharedScheduledExecutors;
22import org.onosproject.core.ApplicationId;
23import org.onosproject.core.CoreService;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070024import org.onosproject.net.behaviour.inbandtelemetry.IntReportConfig;
Carmelo Casconedefc74e2020-07-17 15:27:02 -070025import org.onosproject.net.behaviour.inbandtelemetry.IntMetadataType;
26import org.onosproject.net.behaviour.inbandtelemetry.IntDeviceConfig;
Carmelo Casconefa421582018-09-13 10:05:57 -070027import org.onosproject.inbandtelemetry.api.IntIntent;
28import org.onosproject.inbandtelemetry.api.IntIntentId;
Carmelo Casconedefc74e2020-07-17 15:27:02 -070029import org.onosproject.net.behaviour.inbandtelemetry.IntObjective;
30import org.onosproject.net.behaviour.inbandtelemetry.IntProgrammable;
Carmelo Casconefa421582018-09-13 10:05:57 -070031import org.onosproject.inbandtelemetry.api.IntService;
32import org.onosproject.mastership.MastershipService;
33import org.onosproject.net.ConnectPoint;
34import org.onosproject.net.Device;
35import org.onosproject.net.DeviceId;
36import org.onosproject.net.MastershipRole;
37import org.onosproject.net.PortNumber;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070038import org.onosproject.net.config.ConfigFactory;
39import org.onosproject.net.config.NetworkConfigEvent;
40import org.onosproject.net.config.NetworkConfigListener;
41import org.onosproject.net.config.NetworkConfigRegistry;
42import org.onosproject.net.config.NetworkConfigService;
43import org.onosproject.net.config.basics.SubjectFactories;
Carmelo Casconefa421582018-09-13 10:05:57 -070044import org.onosproject.net.device.DeviceEvent;
45import org.onosproject.net.device.DeviceListener;
46import org.onosproject.net.device.DeviceService;
47import org.onosproject.net.host.HostEvent;
48import org.onosproject.net.host.HostListener;
49import org.onosproject.net.host.HostService;
50import org.onosproject.store.serializers.KryoNamespaces;
51import org.onosproject.store.service.AtomicIdGenerator;
52import org.onosproject.store.service.AtomicValue;
53import org.onosproject.store.service.AtomicValueEvent;
54import org.onosproject.store.service.AtomicValueEventListener;
55import org.onosproject.store.service.ConsistentMap;
56import org.onosproject.store.service.MapEvent;
57import org.onosproject.store.service.MapEventListener;
58import org.onosproject.store.service.Serializer;
59import org.onosproject.store.service.StorageService;
60import org.onosproject.store.service.Versioned;
Ray Milkeydb57f1c2018-10-09 10:39:29 -070061import org.osgi.service.component.annotations.Activate;
62import org.osgi.service.component.annotations.Component;
63import org.osgi.service.component.annotations.Deactivate;
64import org.osgi.service.component.annotations.Reference;
65import org.osgi.service.component.annotations.ReferenceCardinality;
Carmelo Casconefa421582018-09-13 10:05:57 -070066import org.slf4j.Logger;
67
Carmelo Casconefa421582018-09-13 10:05:57 -070068import java.util.Map;
69import java.util.Optional;
70import java.util.Set;
71import java.util.concurrent.ConcurrentMap;
72import java.util.concurrent.ExecutionException;
73import java.util.concurrent.ScheduledFuture;
74import java.util.concurrent.TimeUnit;
75import java.util.concurrent.TimeoutException;
76import java.util.concurrent.locks.Lock;
77import java.util.stream.Collectors;
78
79import static com.google.common.base.Preconditions.checkNotNull;
80import static org.slf4j.LoggerFactory.getLogger;
81
82/**
83 * Simple implementation of IntService, for controlling INT-capable pipelines.
84 * <p>
85 * All INT intents are converted to an equivalent INT objective and applied to
86 * all SOURCE_SINK devices. A device is deemed SOURCE_SINK if it has at least
87 * one host attached.
88 * <p>
89 * The implementation listens for different types of events and when required it
90 * configures a device by cleaning-up any previous state and applying the new
91 * one.
92 */
Ray Milkeydb57f1c2018-10-09 10:39:29 -070093@Component(immediate = true, service = IntService.class)
Carmelo Casconefa421582018-09-13 10:05:57 -070094public class SimpleIntManager implements IntService {
95
96 private final Logger log = getLogger(getClass());
97
98 private static final int CONFIG_EVENT_DELAY = 5; // Seconds.
99
100 private static final String APP_NAME = "org.onosproject.inbandtelemetry";
101
Ray Milkeydb57f1c2018-10-09 10:39:29 -0700102 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng4027cac2020-10-13 19:15:12 -0700103 protected CoreService coreService;
Carmelo Casconefa421582018-09-13 10:05:57 -0700104
Ray Milkeydb57f1c2018-10-09 10:39:29 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng4027cac2020-10-13 19:15:12 -0700106 protected DeviceService deviceService;
Carmelo Casconefa421582018-09-13 10:05:57 -0700107
Ray Milkeydb57f1c2018-10-09 10:39:29 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng4027cac2020-10-13 19:15:12 -0700109 protected StorageService storageService;
Carmelo Casconefa421582018-09-13 10:05:57 -0700110
Ray Milkeydb57f1c2018-10-09 10:39:29 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng4027cac2020-10-13 19:15:12 -0700112 protected MastershipService mastershipService;
Carmelo Casconefa421582018-09-13 10:05:57 -0700113
Ray Milkeydb57f1c2018-10-09 10:39:29 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng4027cac2020-10-13 19:15:12 -0700115 protected HostService hostService;
Carmelo Casconefa421582018-09-13 10:05:57 -0700116
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng4027cac2020-10-13 19:15:12 -0700118 protected NetworkConfigService netcfgService;
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tseng4027cac2020-10-13 19:15:12 -0700121 protected NetworkConfigRegistry netcfgRegistry;
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700122
Carmelo Casconefa421582018-09-13 10:05:57 -0700123 private final Striped<Lock> deviceLocks = Striped.lock(10);
124
125 private final ConcurrentMap<DeviceId, ScheduledFuture<?>> scheduledDeviceTasks = Maps.newConcurrentMap();
126
127 // Distributed state.
128 private ConsistentMap<IntIntentId, IntIntent> intentMap;
129 private ConsistentMap<DeviceId, Long> devicesToConfigure;
Carmelo Casconedefc74e2020-07-17 15:27:02 -0700130 private AtomicValue<IntDeviceConfig> intConfig;
Carmelo Casconefa421582018-09-13 10:05:57 -0700131 private AtomicValue<Boolean> intStarted;
132 private AtomicIdGenerator intentIds;
133
134 // Event listeners.
135 private final InternalHostListener hostListener = new InternalHostListener();
136 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
137 private final InternalIntentMapListener intentMapListener = new InternalIntentMapListener();
138 private final InternalIntConfigListener intConfigListener = new InternalIntConfigListener();
139 private final InternalIntStartedListener intStartedListener = new InternalIntStartedListener();
140 private final InternalDeviceToConfigureListener devicesToConfigureListener =
141 new InternalDeviceToConfigureListener();
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700142 private final NetworkConfigListener appConfigListener = new IntAppConfigListener();
143
144 private final ConfigFactory<ApplicationId, IntReportConfig> intAppConfigFactory =
145 new ConfigFactory<>(SubjectFactories.APP_SUBJECT_FACTORY,
146 IntReportConfig.class, "report") {
147 @Override
148 public IntReportConfig createConfig() {
149 return new IntReportConfig();
150 }
151 };
Carmelo Casconefa421582018-09-13 10:05:57 -0700152
153 @Activate
154 public void activate() {
155
156 final ApplicationId appId = coreService.registerApplication(APP_NAME);
157
158 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
159 .register(KryoNamespaces.API)
160 .register(IntIntent.class)
161 .register(IntIntentId.class)
162 .register(IntDeviceRole.class)
163 .register(IntIntent.IntHeaderType.class)
Carmelo Casconedefc74e2020-07-17 15:27:02 -0700164 .register(IntMetadataType.class)
Carmelo Casconefa421582018-09-13 10:05:57 -0700165 .register(IntIntent.IntReportType.class)
166 .register(IntIntent.TelemetryMode.class)
Carmelo Casconedefc74e2020-07-17 15:27:02 -0700167 .register(IntDeviceConfig.class)
168 .register(IntDeviceConfig.TelemetrySpec.class);
Carmelo Casconefa421582018-09-13 10:05:57 -0700169
170 devicesToConfigure = storageService.<DeviceId, Long>consistentMapBuilder()
171 .withSerializer(Serializer.using(serializer.build()))
172 .withName("onos-int-devices-to-configure")
173 .withApplicationId(appId)
174 .withPurgeOnUninstall()
175 .build();
176 devicesToConfigure.addListener(devicesToConfigureListener);
177
178 intentMap = storageService.<IntIntentId, IntIntent>consistentMapBuilder()
179 .withSerializer(Serializer.using(serializer.build()))
180 .withName("onos-int-intents")
181 .withApplicationId(appId)
182 .withPurgeOnUninstall()
183 .build();
184 intentMap.addListener(intentMapListener);
185
186 intStarted = storageService.<Boolean>atomicValueBuilder()
187 .withSerializer(Serializer.using(serializer.build()))
188 .withName("onos-int-started")
189 .withApplicationId(appId)
190 .build()
191 .asAtomicValue();
192 intStarted.addListener(intStartedListener);
193
Carmelo Casconedefc74e2020-07-17 15:27:02 -0700194 intConfig = storageService.<IntDeviceConfig>atomicValueBuilder()
Carmelo Casconefa421582018-09-13 10:05:57 -0700195 .withSerializer(Serializer.using(serializer.build()))
196 .withName("onos-int-config")
197 .withApplicationId(appId)
198 .build()
199 .asAtomicValue();
200 intConfig.addListener(intConfigListener);
201
202 intentIds = storageService.getAtomicIdGenerator("int-intent-id-generator");
203
204 // Bootstrap config for already existing devices.
205 triggerAllDeviceConfigure();
206
207 hostService.addListener(hostListener);
208 deviceService.addListener(deviceListener);
209
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700210 netcfgRegistry.registerConfigFactory(intAppConfigFactory);
211 netcfgService.addListener(appConfigListener);
Yi Tseng930b0cd2020-10-04 22:33:22 -0700212 // Initialize the INT report
213 IntReportConfig reportConfig = netcfgService.getConfig(appId, IntReportConfig.class);
214 if (reportConfig != null) {
215 IntDeviceConfig intDeviceConfig = IntDeviceConfig.builder()
216 .withMinFlowHopLatencyChangeNs(reportConfig.minFlowHopLatencyChangeNs())
217 .withCollectorPort(reportConfig.collectorPort())
218 .withCollectorIp(reportConfig.collectorIp())
219 .enabled(true)
220 .build();
221 setConfig(intDeviceConfig);
222 }
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700223
Carmelo Casconefa421582018-09-13 10:05:57 -0700224 startInt();
Yi Tseng930b0cd2020-10-04 22:33:22 -0700225 log.info("Started");
Carmelo Casconefa421582018-09-13 10:05:57 -0700226 }
227
228 @Deactivate
229 public void deactivate() {
230 deviceService.removeListener(deviceListener);
231 hostService.removeListener(hostListener);
232 intentIds = null;
233 intConfig.removeListener(intConfigListener);
234 intConfig = null;
235 intStarted.removeListener(intStartedListener);
236 intStarted = null;
237 intentMap.removeListener(intentMapListener);
238 intentMap = null;
239 devicesToConfigure.removeListener(devicesToConfigureListener);
240 devicesToConfigure.destroy();
241 devicesToConfigure = null;
242 // Cancel tasks (if any).
243 scheduledDeviceTasks.values().forEach(f -> {
244 f.cancel(true);
245 if (!f.isDone()) {
246 try {
247 f.get(1, TimeUnit.SECONDS);
248 } catch (InterruptedException | ExecutionException | TimeoutException e) {
249 // Don't care, we are terminating the service anyways.
250 }
251 }
252 });
253 // Clean up INT rules from existing devices.
254 deviceService.getDevices().forEach(d -> cleanupDevice(d.id()));
Yi Tseng930b0cd2020-10-04 22:33:22 -0700255 netcfgService.removeListener(appConfigListener);
256 netcfgRegistry.unregisterConfigFactory(intAppConfigFactory);
Carmelo Casconefa421582018-09-13 10:05:57 -0700257 log.info("Deactivated");
258 }
259
260 @Override
261 public void startInt() {
262 // Atomic value event will trigger device configure.
263 intStarted.set(true);
264 }
265
266 @Override
267 public void startInt(Set<DeviceId> deviceIds) {
268 log.warn("Starting INT for a subset of devices is not supported");
269 }
270
271 @Override
272 public void stopInt() {
273 // Atomic value event will trigger device configure.
274 intStarted.set(false);
275 }
276
277 @Override
278 public void stopInt(Set<DeviceId> deviceIds) {
279 log.warn("Stopping INT for a subset of devices is not supported");
280 }
281
282 @Override
Carmelo Casconedefc74e2020-07-17 15:27:02 -0700283 public void setConfig(IntDeviceConfig cfg) {
Carmelo Casconefa421582018-09-13 10:05:57 -0700284 checkNotNull(cfg);
285 // Atomic value event will trigger device configure.
286 intConfig.set(cfg);
287 }
288
289 @Override
Carmelo Casconedefc74e2020-07-17 15:27:02 -0700290 public IntDeviceConfig getConfig() {
Carmelo Casconefa421582018-09-13 10:05:57 -0700291 return intConfig.get();
292 }
293
294 @Override
295 public IntIntentId installIntIntent(IntIntent intent) {
296 checkNotNull(intent);
297 final Integer intentId = (int) intentIds.nextId();
298 final IntIntentId intIntentId = IntIntentId.valueOf(intentId);
299 // Intent map event will trigger device configure.
300 intentMap.put(intIntentId, intent);
301 return intIntentId;
302 }
303
304 @Override
305 public void removeIntIntent(IntIntentId intentId) {
306 checkNotNull(intentId);
307 // Intent map event will trigger device configure.
Yi Tseng930b0cd2020-10-04 22:33:22 -0700308 if (!intentMap.containsKey(intentId)) {
309 log.warn("INT intent {} does not exists, skip removing the intent.", intentId);
310 return;
311 }
312 intentMap.remove(intentId);
Carmelo Casconefa421582018-09-13 10:05:57 -0700313 }
314
315 @Override
316 public IntIntent getIntIntent(IntIntentId intentId) {
317 return Optional.ofNullable(intentMap.get(intentId).value()).orElse(null);
318 }
319
320 @Override
321 public Map<IntIntentId, IntIntent> getIntIntents() {
322 return intentMap.asJavaMap();
323 }
324
325 private boolean isConfigTaskValid(DeviceId deviceId, long creationTime) {
326 Versioned<?> versioned = devicesToConfigure.get(deviceId);
327 return versioned != null && versioned.creationTime() == creationTime;
328 }
329
330 private boolean isIntStarted() {
331 return intStarted.get();
332 }
333
334 private boolean isNotIntConfigured() {
335 return intConfig.get() == null;
336 }
337
338 private boolean isIntProgrammable(DeviceId deviceId) {
339 final Device device = deviceService.getDevice(deviceId);
340 return device != null && device.is(IntProgrammable.class);
341 }
342
343 private void triggerDeviceConfigure(DeviceId deviceId) {
344 if (isIntProgrammable(deviceId)) {
345 devicesToConfigure.put(deviceId, System.nanoTime());
346 }
347 }
348
349 private void triggerAllDeviceConfigure() {
350 deviceService.getDevices().forEach(d -> triggerDeviceConfigure(d.id()));
351 }
352
353 private void configDeviceTask(DeviceId deviceId, long creationTime) {
354 if (isConfigTaskValid(deviceId, creationTime)) {
355 // Task outdated.
356 return;
357 }
358 if (!deviceService.isAvailable(deviceId)) {
359 return;
360 }
361 final MastershipRole role = mastershipService.requestRoleForSync(deviceId);
362 if (!role.equals(MastershipRole.MASTER)) {
363 return;
364 }
365 deviceLocks.get(deviceId).lock();
366 try {
367 // Clean up first.
368 cleanupDevice(deviceId);
369 if (!configDevice(deviceId)) {
370 // Clean up if fails.
371 cleanupDevice(deviceId);
372 return;
373 }
374 devicesToConfigure.remove(deviceId);
375 } finally {
376 deviceLocks.get(deviceId).unlock();
377 }
378 }
379
380 private void cleanupDevice(DeviceId deviceId) {
381 final Device device = deviceService.getDevice(deviceId);
382 if (device == null || !device.is(IntProgrammable.class)) {
383 return;
384 }
385 device.as(IntProgrammable.class).cleanup();
386 }
387
Yi Tseng4027cac2020-10-13 19:15:12 -0700388 protected boolean configDevice(DeviceId deviceId) {
Carmelo Casconefa421582018-09-13 10:05:57 -0700389 // Returns true if config was successful, false if not and a clean up is
390 // needed.
391 final Device device = deviceService.getDevice(deviceId);
392 if (device == null || !device.is(IntProgrammable.class)) {
393 return true;
394 }
395
396 if (isNotIntConfigured()) {
397 log.warn("Missing INT config, aborting programming of INT device {}", deviceId);
398 return true;
399 }
400
401 final boolean isEdge = !hostService.getConnectedHosts(deviceId).isEmpty();
Yi Tseng4027cac2020-10-13 19:15:12 -0700402 final IntDeviceRole intDeviceRole =
403 isEdge ? IntDeviceRole.SOURCE_SINK : IntDeviceRole.TRANSIT;
Carmelo Casconefa421582018-09-13 10:05:57 -0700404
405 log.info("Started programming of INT device {} with role {}...",
Yi Tseng4027cac2020-10-13 19:15:12 -0700406 deviceId, intDeviceRole);
Carmelo Casconefa421582018-09-13 10:05:57 -0700407
408 final IntProgrammable intProg = device.as(IntProgrammable.class);
409
410 if (!isIntStarted()) {
411 // Leave device with no INT configuration.
412 return true;
413 }
414
415 if (!intProg.init()) {
416 log.warn("Unable to init INT pipeline on {}", deviceId);
417 return false;
418 }
419
Yi Tseng4027cac2020-10-13 19:15:12 -0700420 boolean supportSource = intProg.supportsFunctionality(IntProgrammable.IntFunctionality.SOURCE);
421 boolean supportSink = intProg.supportsFunctionality(IntProgrammable.IntFunctionality.SINK);
422 boolean supportPostcard = intProg.supportsFunctionality(IntProgrammable.IntFunctionality.POSTCARD);
423
424 if (intDeviceRole != IntDeviceRole.SOURCE_SINK && !supportPostcard) {
425 // Stop here, no more configuration needed for transit devices unless it support postcard.
Carmelo Casconefa421582018-09-13 10:05:57 -0700426 return true;
427 }
428
Yi Tseng4027cac2020-10-13 19:15:12 -0700429 if (supportSink || supportPostcard) {
Carmelo Casconefa421582018-09-13 10:05:57 -0700430 if (!intProg.setupIntConfig(intConfig.get())) {
431 log.warn("Unable to apply INT report config on {}", deviceId);
432 return false;
433 }
434 }
435
436 // Port configuration.
437 final Set<PortNumber> hostPorts = deviceService.getPorts(deviceId)
438 .stream()
439 .map(port -> new ConnectPoint(deviceId, port.number()))
440 .filter(cp -> !hostService.getConnectedHosts(cp).isEmpty())
441 .map(ConnectPoint::port)
442 .collect(Collectors.toSet());
443
444 for (PortNumber port : hostPorts) {
Yi Tseng4027cac2020-10-13 19:15:12 -0700445 if (supportSource) {
Carmelo Casconefa421582018-09-13 10:05:57 -0700446 log.info("Setting port {}/{} as INT source port...", deviceId, port);
447 if (!intProg.setSourcePort(port)) {
448 log.warn("Unable to set INT source port {} on {}", port, deviceId);
449 return false;
450 }
451 }
Yi Tseng4027cac2020-10-13 19:15:12 -0700452 if (supportSink) {
Carmelo Casconefa421582018-09-13 10:05:57 -0700453 log.info("Setting port {}/{} as INT sink port...", deviceId, port);
454 if (!intProg.setSinkPort(port)) {
455 log.warn("Unable to set INT sink port {} on {}", port, deviceId);
456 return false;
457 }
458 }
459 }
460
Yi Tseng4027cac2020-10-13 19:15:12 -0700461 if (!supportSource && !supportPostcard) {
462 // Stop here, no more configuration needed for sink devices unless
463 // it supports postcard mode.
Carmelo Casconefa421582018-09-13 10:05:57 -0700464 return true;
465 }
466
467 // Apply intents.
468 // This is a trivial implementation where we simply get the
Yi Tseng4027cac2020-10-13 19:15:12 -0700469 // corresponding INT objective from an intent and we apply to all
470 // device which support reporting.
Carmelo Casconefa421582018-09-13 10:05:57 -0700471 int appliedCount = 0;
Yi Tseng4027cac2020-10-13 19:15:12 -0700472 for (Versioned<IntIntent> versionedIntent : intentMap.values()) {
473 IntIntent intent = versionedIntent.value();
474 IntObjective intObjective = getIntObjective(intent);
475 if (intent.telemetryMode() == IntIntent.TelemetryMode.INBAND_TELEMETRY && supportSource) {
476 intProg.addIntObjective(intObjective);
477 appliedCount++;
478 } else if (intent.telemetryMode() == IntIntent.TelemetryMode.POSTCARD && supportPostcard) {
479 intProg.addIntObjective(intObjective);
480 appliedCount++;
481 } else {
482 log.warn("Device {} does not support intent {}.", deviceId, intent);
Carmelo Casconefa421582018-09-13 10:05:57 -0700483 }
484 }
Carmelo Casconefa421582018-09-13 10:05:57 -0700485 log.info("Completed programming of {}, applied {} INT objectives of {} total",
Yi Tseng4027cac2020-10-13 19:15:12 -0700486 deviceId, appliedCount, intentMap.size());
Carmelo Casconefa421582018-09-13 10:05:57 -0700487 return true;
488 }
489
490 private IntObjective getIntObjective(IntIntent intent) {
Carmelo Casconedefc74e2020-07-17 15:27:02 -0700491 // FIXME: we are ignore intent.headerType()
492 // what should we do with it?
Carmelo Casconefa421582018-09-13 10:05:57 -0700493 return new IntObjective.Builder()
494 .withSelector(intent.selector())
495 .withMetadataTypes(intent.metadataTypes())
Carmelo Casconefa421582018-09-13 10:05:57 -0700496 .build();
497 }
498
499 /* Event listeners which trigger device configuration. */
500
501 private class InternalHostListener implements HostListener {
502 @Override
503 public void event(HostEvent event) {
504 final DeviceId deviceId = event.subject().location().deviceId();
505 triggerDeviceConfigure(deviceId);
506 }
507 }
508
509 private class InternalDeviceListener implements DeviceListener {
510 @Override
511 public void event(DeviceEvent event) {
512 switch (event.type()) {
513 case DEVICE_ADDED:
514 case DEVICE_UPDATED:
515 case DEVICE_REMOVED:
516 case DEVICE_SUSPENDED:
517 case DEVICE_AVAILABILITY_CHANGED:
518 case PORT_ADDED:
519 case PORT_UPDATED:
520 case PORT_REMOVED:
521 triggerDeviceConfigure(event.subject().id());
522 return;
523 case PORT_STATS_UPDATED:
524 return;
525 default:
526 log.warn("Unknown device event type {}", event.type());
527 }
528 }
529 }
530
531 private class InternalIntentMapListener
532 implements MapEventListener<IntIntentId, IntIntent> {
533 @Override
534 public void event(MapEvent<IntIntentId, IntIntent> event) {
535 triggerAllDeviceConfigure();
536 }
537 }
538
539 private class InternalIntConfigListener
Carmelo Casconedefc74e2020-07-17 15:27:02 -0700540 implements AtomicValueEventListener<IntDeviceConfig> {
Carmelo Casconefa421582018-09-13 10:05:57 -0700541 @Override
Carmelo Casconedefc74e2020-07-17 15:27:02 -0700542 public void event(AtomicValueEvent<IntDeviceConfig> event) {
Carmelo Casconefa421582018-09-13 10:05:57 -0700543 triggerAllDeviceConfigure();
544 }
545 }
546
547 private class InternalIntStartedListener
548 implements AtomicValueEventListener<Boolean> {
549 @Override
550 public void event(AtomicValueEvent<Boolean> event) {
551 triggerAllDeviceConfigure();
552 }
553 }
554
555 private class InternalDeviceToConfigureListener
556 implements MapEventListener<DeviceId, Long> {
557 @Override
558 public void event(MapEvent<DeviceId, Long> event) {
559 if (event.type().equals(MapEvent.Type.REMOVE) ||
560 event.newValue() == null) {
561 return;
562 }
563 // Schedule task in the future. Wait for events for this device to
564 // stabilize.
565 final DeviceId deviceId = event.key();
566 final long creationTime = event.newValue().creationTime();
567 ScheduledFuture<?> newTask = SharedScheduledExecutors.newTimeout(
568 () -> configDeviceTask(deviceId, creationTime),
569 CONFIG_EVENT_DELAY, TimeUnit.SECONDS);
570 ScheduledFuture<?> oldTask = scheduledDeviceTasks.put(deviceId, newTask);
571 if (oldTask != null) {
572 oldTask.cancel(false);
573 }
574 }
575 }
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700576
577 private class IntAppConfigListener implements NetworkConfigListener {
578
579 @Override
580 public void event(NetworkConfigEvent event) {
581 switch (event.type()) {
582 case CONFIG_ADDED:
583 case CONFIG_UPDATED:
584 event.config()
585 .map(config -> (IntReportConfig) config)
586 .ifPresent(config -> {
587 IntDeviceConfig intDeviceConfig = IntDeviceConfig.builder()
588 .withMinFlowHopLatencyChangeNs(config.minFlowHopLatencyChangeNs())
589 .withCollectorPort(config.collectorPort())
590 .withCollectorIp(config.collectorIp())
591 .enabled(true)
592 .build();
593 setConfig(intDeviceConfig);
594 });
595 break;
596 // TODO: Support removing INT config.
597 default:
598 break;
599 }
600 }
601
602 @Override
603 public boolean isRelevant(NetworkConfigEvent event) {
604 return event.configClass() == IntReportConfig.class;
605 }
606 }
Carmelo Casconefa421582018-09-13 10:05:57 -0700607}