blob: b02fb52f0dc5bce77280c9fc0dd083ed269bd8db [file] [log] [blame]
Hyunsun Moon5401aaa2016-06-12 17:40:34 -07001/*
2 * Copyright 2015-present Open Networking Laboratory
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.opencord.cordvtn.impl;
17
18import com.google.common.collect.Sets;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
25import org.onlab.packet.Ip4Address;
26import org.onlab.packet.MacAddress;
27import org.onlab.packet.VlanId;
Hyunsun Moon1e88fef2016-08-04 14:00:35 -070028import org.opencord.cordconfig.CordConfigService;
29import org.opencord.cordconfig.access.AccessAgentData;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070030import org.opencord.cordvtn.api.CordVtnConfig;
31import org.opencord.cordvtn.api.Instance;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.dhcp.DhcpService;
35import org.onosproject.dhcp.IpAssignment;
36import org.onosproject.net.ConnectPoint;
37import org.onosproject.net.DefaultAnnotations;
38import org.onosproject.net.Host;
39import org.onosproject.net.HostId;
40import org.onosproject.net.HostLocation;
41import org.onosproject.net.Port;
42import org.onosproject.net.config.ConfigFactory;
43import org.onosproject.net.config.NetworkConfigEvent;
44import org.onosproject.net.config.NetworkConfigListener;
45import org.onosproject.net.config.NetworkConfigRegistry;
46import org.onosproject.net.config.basics.SubjectFactories;
47import org.onosproject.net.device.DeviceService;
48import org.onosproject.net.host.DefaultHostDescription;
49import org.onosproject.net.host.HostDescription;
50import org.onosproject.net.host.HostProvider;
51import org.onosproject.net.host.HostProviderRegistry;
52import org.onosproject.net.host.HostProviderService;
53import org.onosproject.net.host.HostService;
54import org.onosproject.net.provider.AbstractProvider;
55import org.onosproject.net.provider.ProviderId;
56import org.onosproject.xosclient.api.OpenStackAccess;
57import org.onosproject.xosclient.api.VtnPort;
58import org.onosproject.xosclient.api.VtnPortApi;
59import org.onosproject.xosclient.api.VtnService;
60import org.onosproject.xosclient.api.VtnServiceApi;
61import org.onosproject.xosclient.api.VtnServiceId;
62import org.onosproject.xosclient.api.XosAccess;
63import org.onosproject.xosclient.api.XosClientService;
64import org.opencord.cordvtn.api.InstanceService;
65import org.slf4j.Logger;
66
67import java.util.Date;
Hyunsun Moon1e88fef2016-08-04 14:00:35 -070068import java.util.Optional;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070069import java.util.concurrent.ExecutorService;
70
71import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon537018f2016-07-27 18:51:00 -070072import static java.util.concurrent.Executors.newSingleThreadExecutor;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070073import static org.onlab.util.Tools.groupedThreads;
74import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
Hyunsun Moon81a13562016-08-04 13:48:08 -070075import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Moon1e88fef2016-08-04 14:00:35 -070076import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.ACCESS_AGENT;
Hyunsun Moon8af93512016-08-04 13:40:58 -070077import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.MANAGEMENT;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070078import static org.opencord.cordvtn.api.Constants.*;
79import static org.slf4j.LoggerFactory.getLogger;
80
81/**
82 * Adds or removes instances to network services.
83 */
84@Component(immediate = true)
85@Service
86public class InstanceManager extends AbstractProvider implements HostProvider,
87 InstanceService {
88
89 protected final Logger log = getLogger(getClass());
90
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070091 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected CoreService coreService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected NetworkConfigRegistry configRegistry;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected HostProviderRegistry hostProviderRegistry;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected DeviceService deviceService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected HostService hostService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected DhcpService dhcpService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected XosClientService xosClient;
111
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700112 // TODO get access agent container information from XOS
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected CordConfigService cordConfig;
115
116 private static final Class<CordVtnConfig> CONFIG_CLASS = CordVtnConfig.class;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700117 private final ConfigFactory configFactory =
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700118 new ConfigFactory<ApplicationId, CordVtnConfig>(
119 SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "cordvtn") {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700120 @Override
121 public CordVtnConfig createConfig() {
122 return new CordVtnConfig();
123 }
124 };
125
126 private final ExecutorService eventExecutor =
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700127 newSingleThreadExecutor(groupedThreads(this.getClass().getSimpleName(), "event-handler"));
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700128 private final NetworkConfigListener configListener = new InternalConfigListener();
129
130 private ApplicationId appId;
131 private HostProviderService hostProvider;
132 private XosAccess xosAccess = null;
133 private OpenStackAccess osAccess = null;
134
135 /**
136 * Creates an cordvtn host location provider.
137 */
138 public InstanceManager() {
139 super(new ProviderId("host", CORDVTN_APP_ID));
140 }
141
142 @Activate
143 protected void activate() {
144 appId = coreService.registerApplication(CORDVTN_APP_ID);
145
146 hostProvider = hostProviderRegistry.register(this);
147 configRegistry.registerConfigFactory(configFactory);
148 configRegistry.addListener(configListener);
149
150 log.info("Started");
151 }
152
153 @Deactivate
154 protected void deactivate() {
155 hostProviderRegistry.unregister(this);
156
157 configRegistry.unregisterConfigFactory(configFactory);
158 configRegistry.removeListener(configListener);
159
160 eventExecutor.shutdown();
161 log.info("Stopped");
162 }
163
164 @Override
165 public void triggerProbe(Host host) {
166 /*
167 * Note: In CORD deployment, we assume that all hosts are configured.
168 * Therefore no probe is required.
169 */
170 }
171
172 @Override
173 public void addInstance(ConnectPoint connectPoint) {
174 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
175 if (port == null) {
176 log.debug("No port found from {}", connectPoint);
177 return;
178 }
179
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700180 // TODO remove this when XOS provides access agent information
181 // and handle it the same way wit the other instances
182 if (isAccessAgent(connectPoint)) {
183 addAccessAgentInstance(connectPoint);
184 return;
185 }
186
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700187 VtnPort vtnPort = getVtnPort(port.annotations().value(PORT_NAME));
188 if (vtnPort == null) {
189 return;
190 }
191
192 VtnService vtnService = getVtnService(vtnPort.serviceId());
193 if (vtnService == null) {
194 return;
195 }
196
197 // register DHCP lease for the new instance
198 registerDhcpLease(vtnPort.mac(), vtnPort.ip().getIp4Address(), vtnService);
199
200 // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
201 // existing instances.
202 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
203 .set(Instance.SERVICE_TYPE, vtnService.serviceType().toString())
204 .set(Instance.SERVICE_ID, vtnPort.serviceId().id())
205 .set(Instance.PORT_ID, vtnPort.id().id())
206 .set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
207
208 HostDescription hostDesc = new DefaultHostDescription(
209 vtnPort.mac(),
210 VlanId.NONE,
211 new HostLocation(connectPoint, System.currentTimeMillis()),
212 Sets.newHashSet(vtnPort.ip()),
213 annotations.build());
214
215 HostId hostId = HostId.hostId(vtnPort.mac());
216 hostProvider.hostDetected(hostId, hostDesc, false);
217 }
218
219 @Override
220 public void addNestedInstance(HostId hostId, HostDescription description) {
221 DefaultAnnotations annotations = DefaultAnnotations.builder()
222 .set(Instance.NESTED_INSTANCE, Instance.TRUE)
223 .build();
224 annotations = annotations.merge(annotations, description.annotations());
225
226 HostDescription nestedHost = new DefaultHostDescription(
227 description.hwAddress(),
228 description.vlan(),
229 description.location(),
230 description.ipAddress(),
231 annotations);
232
233 hostProvider.hostDetected(hostId, nestedHost, false);
234 }
235
236 @Override
237 public void removeInstance(ConnectPoint connectPoint) {
238 hostService.getConnectedHosts(connectPoint).stream()
239 .forEach(host -> {
240 dhcpService.removeStaticMapping(host.mac());
241 hostProvider.hostVanished(host.id());
242 });
243 }
244
245 @Override
246 public void removeNestedInstance(HostId hostId) {
247 hostProvider.hostVanished(hostId);
248 }
249
250 private void registerDhcpLease(MacAddress macAddr, Ip4Address ipAddr, VtnService service) {
251 Ip4Address broadcast = Ip4Address.makeMaskedAddress(
252 ipAddr,
253 service.subnet().prefixLength());
254
255 IpAssignment.Builder ipBuilder = IpAssignment.builder()
256 .ipAddress(ipAddr)
257 .leasePeriod(DHCP_INFINITE_LEASE)
258 .timestamp(new Date())
259 .subnetMask(Ip4Address.makeMaskPrefix(service.subnet().prefixLength()))
260 .broadcast(broadcast)
261 .domainServer(DEFAULT_DNS)
262 .assignmentStatus(Option_RangeNotEnforced);
263
Hyunsun Moon8af93512016-08-04 13:40:58 -0700264 if (service.serviceType() != MANAGEMENT) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700265 ipBuilder = ipBuilder.routerAddress(service.serviceIp().getIp4Address());
266 }
267
268 log.debug("Set static DHCP mapping for {} {}", macAddr, ipAddr);
269 dhcpService.setStaticMapping(macAddr, ipBuilder.build());
270 }
271
272 private VtnService getVtnService(VtnServiceId serviceId) {
273 checkNotNull(osAccess, ERROR_OPENSTACK_ACCESS);
274 checkNotNull(xosAccess, ERROR_XOS_ACCESS);
275
276 // TODO remove openstack access when XOS provides all information
277 VtnServiceApi serviceApi = xosClient.getClient(xosAccess).vtnService();
278 VtnService service = serviceApi.service(serviceId, osAccess);
279 if (service == null) {
280 log.warn("Failed to get VtnService for {}", serviceId);
281 }
282 return service;
283 }
284
285 private VtnPort getVtnPort(String portName) {
286 checkNotNull(osAccess, ERROR_OPENSTACK_ACCESS);
287 checkNotNull(xosAccess, ERROR_XOS_ACCESS);
288
289 // TODO remove openstack access when XOS provides all information
290 VtnPortApi portApi = xosClient.getClient(xosAccess).vtnPort();
291 VtnPort vtnPort = portApi.vtnPort(portName, osAccess);
292 if (vtnPort == null) {
293 log.warn("Failed to get port information of {}", portName);
294 }
295 return vtnPort;
296 }
297
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700298 // TODO remove this when XOS provides access agent information
299 private boolean isAccessAgent(ConnectPoint connectPoint) {
300 Optional<AccessAgentData> agent = cordConfig.getAccessAgent(connectPoint.deviceId());
301 if (!agent.isPresent() || !agent.get().getVtnLocation().isPresent()) {
302 return false;
303 }
304 return agent.get().getVtnLocation().get().port().equals(connectPoint.port());
305 }
306
307 // TODO remove this when XOS provides access agent information
308 private void addAccessAgentInstance(ConnectPoint connectPoint) {
309 AccessAgentData agent = cordConfig.getAccessAgent(connectPoint.deviceId()).get();
310 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
311 .set(Instance.SERVICE_TYPE, ACCESS_AGENT.name())
312 .set(Instance.SERVICE_ID, NOT_APPLICABLE)
313 .set(Instance.PORT_ID, NOT_APPLICABLE)
314 .set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
315
316 HostDescription hostDesc = new DefaultHostDescription(
317 agent.getAgentMac(),
318 VlanId.NONE,
319 new HostLocation(connectPoint, System.currentTimeMillis()),
320 Sets.newHashSet(),
321 annotations.build());
322
323 HostId hostId = HostId.hostId(agent.getAgentMac());
324 hostProvider.hostDetected(hostId, hostDesc, false);
325 }
326
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700327 private void readConfiguration() {
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700328 CordVtnConfig config = configRegistry.getConfig(appId, CONFIG_CLASS);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700329 if (config == null) {
330 log.debug("No configuration found");
331 return;
332 }
333
334 log.info("Load CORD-VTN configurations");
335 xosAccess = config.xosAccess();
336 osAccess = config.openstackAccess();
337 }
338
339 private class InternalConfigListener implements NetworkConfigListener {
340
341 @Override
342 public void event(NetworkConfigEvent event) {
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700343 if (!event.configClass().equals(CONFIG_CLASS)) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700344 return;
345 }
346
347 switch (event.type()) {
Hyunsun Moonfb417942016-06-23 14:48:20 -0700348 case CONFIG_UPDATED:
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700349 case CONFIG_ADDED:
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700350 readConfiguration();
351 break;
352 default:
353 break;
354 }
355 }
356 }
357}