blob: 5cf32dad6ad9b0ac8fb6a19af1a8384103650e08 [file] [log] [blame]
Jonghwan Hyun13a430d2018-07-22 17:02:51 +09001/*
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 org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.apache.felix.scr.annotations.Service;
24import org.onlab.util.KryoNamespace;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
27import org.onosproject.inbandtelemetry.api.IntConfig;
28import org.onosproject.inbandtelemetry.api.IntIntent;
29import org.onosproject.inbandtelemetry.api.IntIntentId;
30import org.onosproject.inbandtelemetry.api.IntObjective;
31import org.onosproject.inbandtelemetry.api.IntProgrammable;
32import org.onosproject.inbandtelemetry.api.IntService;
33import org.onosproject.net.Device;
34import org.onosproject.net.DeviceId;
35import org.onosproject.net.device.DeviceService;
36import org.onosproject.net.flow.FlowRuleService;
37import org.onosproject.net.host.HostEvent;
38import org.onosproject.net.host.HostListener;
39import org.onosproject.net.host.HostService;
40import org.onosproject.store.serializers.KryoNamespaces;
41import org.onosproject.store.service.AtomicIdGenerator;
42import org.onosproject.store.service.ConsistentMap;
43import org.onosproject.store.service.Serializer;
44import org.onosproject.store.service.StorageService;
45import org.slf4j.Logger;
46
47import java.util.Map;
48import java.util.Optional;
49import java.util.Set;
50
51import static org.slf4j.LoggerFactory.getLogger;
52
53/**
54 * Implementation of IntService, for controlling INT-capable pipelines.
55 */
56@Component(immediate = true)
57@Service
58public class IntManager implements IntService {
59 private final String appName = "org.onosproject.inbandtelemetry";
60 private ApplicationId appId;
61 private final Logger log = getLogger(getClass());
62 private ConsistentMap<IntIntentId, IntIntent> intentConsistentMap;
63 private ConsistentMap<DeviceId, IntDeviceRole> deviceRoleConsistentMap;
64 private IntConfig cfg;
65 private AtomicIdGenerator intentIds;
66
67 private InternalHostListener hostListener = new InternalHostListener();
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 private CoreService coreService;
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 private DeviceService deviceService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 private StorageService storageService;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 private HostService hostService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 private FlowRuleService flowRuleService;
83
84 @Activate
85 public void activate() {
86 appId = coreService.registerApplication(appName);
87
88 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
89 .register(KryoNamespaces.API)
90 .register(IntIntent.class)
91 .register(IntIntentId.class)
92 .register(IntDeviceRole.class)
93 .register(IntIntent.IntHeaderType.class)
94 .register(IntIntent.IntMetadataType.class)
95 .register(IntIntent.IntReportType.class)
96 .register(IntIntent.TelemetryMode.class);
97
98 intentConsistentMap = storageService.<IntIntentId, IntIntent>consistentMapBuilder()
99 .withSerializer(Serializer.using(serializer.build()))
100 .withName("int-intents")
101 .withApplicationId(appId)
102 .withPurgeOnUninstall()
103 .build();
104
105 deviceRoleConsistentMap = storageService.<DeviceId, IntDeviceRole>consistentMapBuilder()
106 .withSerializer(Serializer.using(serializer.build()))
107 .withName("int-device-roles")
108 .withApplicationId(appId)
109 .withPurgeOnUninstall()
110 .build();
111
112 // Assign IntDeviceRole to each device
113 deviceService.getAvailableDevices().forEach(device ->
114 deviceRoleConsistentMap.put(device.id(),
115 hostService.getConnectedHosts(device.id()).isEmpty() ?
116 IntDeviceRole.TRANSIT :
117 IntDeviceRole.SOURCE_SINK)
118 );
119 hostService.addListener(hostListener);
120 intentIds = storageService.getAtomicIdGenerator("int-intent-id-generator");
121 startInt();
122 log.info("Started", appId.id());
123 }
124
125 @Deactivate
126 public void deactivate() {
127 hostService.removeListener(hostListener);
128 log.info("Deactivated");
129 }
130
131 @Override
132 public void startInt() {
133 deviceService.getAvailableDevices().forEach(device -> {
134 if (device.is(IntProgrammable.class)) {
135 IntProgrammable intDevice = device.as(IntProgrammable.class);
136 intDevice.init();
137 }
138 });
139 }
140
141 @Override
142 public void startInt(Set<DeviceId> deviceIds) {
143 deviceIds.forEach(deviceId -> {
144 Device device = deviceService.getDevice(deviceId);
145 if (device.is(IntProgrammable.class) &&
146 getIntRole(deviceId) == IntDeviceRole.TRANSIT) {
147 IntProgrammable intDevice = device.as(IntProgrammable.class);
148 intDevice.init();
149 }
150 });
151 }
152
153 @Override
154 public void stopInt() {
155 flowRuleService.removeFlowRulesById(appId);
156 }
157
158 @Override
159 public void stopInt(Set<DeviceId> deviceIds) {
160
161 }
162
163 @Override
164 public void setConfig(IntConfig cfg) {
165 this.cfg = cfg;
166 deviceService.getAvailableDevices().forEach(device -> {
167 if (device.is(IntProgrammable.class)) {
168 IntProgrammable intDevice = device.as(IntProgrammable.class);
169 intDevice.setupIntConfig(cfg);
170 }
171 });
172 }
173
174 @Override
175 public IntConfig getConfig() {
176 return cfg;
177 }
178
179 @Override
180 public IntIntentId installIntIntent(IntIntent intent) {
181 Integer intentId = (int) intentIds.nextId();
182 IntIntentId intIntentId = IntIntentId.valueOf(intentId);
183 intentConsistentMap.put(intIntentId, intent);
184
185 // Convert IntIntent into an IntObjective
186 IntObjective obj = new IntObjective.Builder()
187 .withSelector(intent.selector())
188 .withMetadataTypes(intent.metadataTypes())
189 .withHeaderType(intent.headerType())
190 .build();
191
192 // Install IntObjective on each INT source device
193 deviceService.getAvailableDevices().forEach(device -> {
194 if (device.is(IntProgrammable.class)
195 && deviceRoleConsistentMap.get(device.id()).value() == IntDeviceRole.SOURCE_SINK) {
196 IntProgrammable intDevice = device.as(IntProgrammable.class);
197 intDevice.addIntObjective(obj);
198 }
199 });
200 return intIntentId;
201 }
202
203 @Override
204 public void removeIntIntent(IntIntentId intentId) {
205 IntIntent intent = intentConsistentMap.remove(intentId).value();
206
207 // Convert IntIntent into an IntObjective
208 IntObjective obj = new IntObjective.Builder()
209 .withSelector(intent.selector())
210 .withMetadataTypes(intent.metadataTypes())
211 .withHeaderType(intent.headerType())
212 .build();
213
214 // Remove IntObjective on each INT source device
215 deviceService.getAvailableDevices().forEach(device -> {
216 if (device.is(IntProgrammable.class)
217 && deviceRoleConsistentMap.get(device.id()).value() == IntDeviceRole.SOURCE_SINK) {
218 IntProgrammable intDevice = device.as(IntProgrammable.class);
219 intDevice.removeIntObjective(obj);
220 }
221 });
222 }
223
224 @Override
225 public IntIntent getIntIntent(IntIntentId intentId) {
226 return Optional.ofNullable(intentConsistentMap.get(intentId).value()).orElse(null);
227 }
228
229 @Override
230 public Map<IntIntentId, IntIntent> getIntIntents() {
231 return intentConsistentMap.asJavaMap();
232 }
233
234 private IntDeviceRole getIntRole(DeviceId deviceId) {
235 return deviceRoleConsistentMap.get(deviceId).value();
236 }
237
238 private void setIntRole(DeviceId deviceId, IntDeviceRole role) {
239 deviceRoleConsistentMap.put(deviceId, role);
240 }
241
242 private class InternalHostListener implements HostListener {
243 @Override
244 public void event(HostEvent event) {
245 DeviceId deviceId = event.subject().location().deviceId();
246 if (!deviceService.getDevice(deviceId).is(IntProgrammable.class)) {
247 return;
248 }
249 switch (event.type()) {
250 case HOST_ADDED:
251 // When a host is attached to the switch, we can configure it
252 // to work as SOURCE_SINK switch.
253 if (deviceRoleConsistentMap.getOrDefault(deviceId, IntDeviceRole.TRANSIT).value()
254 != IntDeviceRole.SOURCE_SINK) {
255 setIntRole(deviceId, IntDeviceRole.SOURCE_SINK);
256 }
257 break;
258 default:
259 break;
260 }
261 }
262 }
263
264}