blob: 74017c8c9d0fd3319c5dae28e2db919375079f8c [file] [log] [blame]
Hyunsun Moon5401aaa2016-06-12 17:40:34 -07001/*
Brian O'Connor80dff972017-08-03 22:46:30 -07002 * Copyright 2015-present Open Networking Foundation
Hyunsun Moon5401aaa2016-06-12 17:40:34 -07003 *
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;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070025import org.onlab.packet.VlanId;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070026import org.onosproject.cluster.ClusterService;
27import org.onosproject.cluster.LeadershipService;
28import org.onosproject.cluster.NodeId;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070029import org.onosproject.core.ApplicationId;
30import org.onosproject.core.CoreService;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070031import org.onosproject.net.ConnectPoint;
32import org.onosproject.net.DefaultAnnotations;
Jonathan Hart39960482017-11-20 15:50:36 -080033import org.onosproject.net.Device;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070034import org.onosproject.net.Host;
35import org.onosproject.net.HostId;
36import org.onosproject.net.HostLocation;
37import org.onosproject.net.Port;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070038import org.onosproject.net.device.DeviceService;
39import org.onosproject.net.host.DefaultHostDescription;
40import org.onosproject.net.host.HostDescription;
41import org.onosproject.net.host.HostProvider;
42import org.onosproject.net.host.HostProviderRegistry;
43import org.onosproject.net.host.HostProviderService;
44import org.onosproject.net.host.HostService;
45import org.onosproject.net.provider.AbstractProvider;
46import org.onosproject.net.provider.ProviderId;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080047import org.opencord.cordconfig.CordConfigService;
48import org.opencord.cordconfig.access.AccessAgentData;
Hyunsun Moon187bf532017-01-19 10:57:40 +090049import org.opencord.cordvtn.api.core.Instance;
50import org.opencord.cordvtn.api.core.InstanceService;
51import org.opencord.cordvtn.api.core.ServiceNetworkEvent;
52import org.opencord.cordvtn.api.core.ServiceNetworkListener;
53import org.opencord.cordvtn.api.core.ServiceNetworkService;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070054import org.opencord.cordvtn.api.net.PortId;
Hyunsun Moon187bf532017-01-19 10:57:40 +090055import org.opencord.cordvtn.api.net.ServiceNetwork;
56import org.opencord.cordvtn.api.net.ServicePort;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070057import org.slf4j.Logger;
58
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070059import java.util.Objects;
Hyunsun Moon1e88fef2016-08-04 14:00:35 -070060import java.util.Optional;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070061import java.util.concurrent.ExecutorService;
Jonathan Hart39960482017-11-20 15:50:36 -080062import java.util.stream.StreamSupport;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070063
Hyunsun Moon537018f2016-07-27 18:51:00 -070064import static java.util.concurrent.Executors.newSingleThreadExecutor;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070065import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon81a13562016-08-04 13:48:08 -070066import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080067import static org.opencord.cordvtn.api.Constants.CORDVTN_APP_ID;
68import static org.opencord.cordvtn.api.Constants.NOT_APPLICABLE;
Hyunsun Moon187bf532017-01-19 10:57:40 +090069import static org.opencord.cordvtn.api.net.ServiceNetwork.NetworkType.ACCESS_AGENT;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070070import static org.slf4j.LoggerFactory.getLogger;
71
72/**
73 * Adds or removes instances to network services.
74 */
75@Component(immediate = true)
76@Service
77public class InstanceManager extends AbstractProvider implements HostProvider,
78 InstanceService {
79
80 protected final Logger log = getLogger(getClass());
Hyunsun Moon187bf532017-01-19 10:57:40 +090081 private static final String ERR_SERVICE_NETWORK = "Failed to get service network for %s";
82 private static final String ERR_SERVICE_PORT = "Failed to get service port for %s";
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070083
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070084 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected CoreService coreService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070088 protected HostProviderRegistry hostProviderRegistry;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected DeviceService deviceService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected HostService hostService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070097 protected LeadershipService leadershipService;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070098
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700100 protected ClusterService clusterService;
101
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700102 // TODO get access agent container information from XOS
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected CordConfigService cordConfig;
105
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon187bf532017-01-19 10:57:40 +0900107 protected ServiceNetworkService snetService;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700108
109 private final ExecutorService eventExecutor =
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700110 newSingleThreadExecutor(groupedThreads(this.getClass().getSimpleName(), "event-handler"));
Hyunsun Moon187bf532017-01-19 10:57:40 +0900111 private final ServiceNetworkListener snetListener = new InternalServiceNetworkListener();
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700112
113 private ApplicationId appId;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700114 private NodeId localNodeId;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700115 private HostProviderService hostProvider;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700116
117 /**
118 * Creates an cordvtn host location provider.
119 */
120 public InstanceManager() {
121 super(new ProviderId("host", CORDVTN_APP_ID));
122 }
123
124 @Activate
125 protected void activate() {
126 appId = coreService.registerApplication(CORDVTN_APP_ID);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700127 localNodeId = clusterService.getLocalNode().id();
128 leadershipService.runForLeadership(appId.name());
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700129
130 hostProvider = hostProviderRegistry.register(this);
Hyunsun Moon187bf532017-01-19 10:57:40 +0900131 snetService.addListener(snetListener);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700132
133 log.info("Started");
134 }
135
136 @Deactivate
137 protected void deactivate() {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900138 snetService.removeListener(snetListener);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700139 hostProviderRegistry.unregister(this);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700140 eventExecutor.shutdown();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700141 leadershipService.withdraw(appId.name());
142
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700143 log.info("Stopped");
144 }
145
146 @Override
147 public void triggerProbe(Host host) {
148 /*
149 * Note: In CORD deployment, we assume that all hosts are configured.
150 * Therefore no probe is required.
151 */
152 }
153
154 @Override
155 public void addInstance(ConnectPoint connectPoint) {
156 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
157 if (port == null) {
158 log.debug("No port found from {}", connectPoint);
159 return;
160 }
161
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700162 // TODO remove this when XOS provides access agent information
163 // and handle it the same way wit the other instances
164 if (isAccessAgent(connectPoint)) {
165 addAccessAgentInstance(connectPoint);
166 return;
167 }
168
Hyunsun Moon187bf532017-01-19 10:57:40 +0900169 ServicePort sport = getServicePortByPortName(port.annotations().value(PORT_NAME));
170 if (sport == null) {
171 log.warn(String.format(ERR_SERVICE_PORT, port));
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700172 return;
173 }
174
Hyunsun Moon187bf532017-01-19 10:57:40 +0900175 ServiceNetwork snet = snetService.serviceNetwork(sport.networkId());
176 if (snet == null) {
177 final String error = String.format(ERR_SERVICE_NETWORK, sport);
178 throw new IllegalStateException(error);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700179 }
180
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700181 // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
Hyunsun Moon187bf532017-01-19 10:57:40 +0900182 // existing instances. Fix this after adding a method to update/reinstall
183 // flow rules for the existing service instances.
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700184 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Moon187bf532017-01-19 10:57:40 +0900185 .set(Instance.NETWORK_TYPE, snet.type().name())
186 .set(Instance.NETWORK_ID, snet.id().id())
187 .set(Instance.PORT_ID, sport.id().id())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700188 .set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
189
190 HostDescription hostDesc = new DefaultHostDescription(
Hyunsun Moon187bf532017-01-19 10:57:40 +0900191 sport.mac(),
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700192 VlanId.NONE,
193 new HostLocation(connectPoint, System.currentTimeMillis()),
Hyunsun Moon187bf532017-01-19 10:57:40 +0900194 Sets.newHashSet(sport.ip()),
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700195 annotations.build());
196
Hyunsun Moon187bf532017-01-19 10:57:40 +0900197 HostId hostId = HostId.hostId(sport.mac());
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700198 hostProvider.hostDetected(hostId, hostDesc, false);
199 }
200
201 @Override
Hyunsun Moond02a5a72017-02-05 22:00:05 +0900202 public void addInstance(HostId hostId, HostDescription description) {
203 hostProvider.hostDetected(hostId, description, false);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700204 }
205
206 @Override
207 public void removeInstance(ConnectPoint connectPoint) {
Hyunsun Moon851e57f2017-02-23 19:38:40 +0900208 hostService.getConnectedHosts(connectPoint).forEach(host -> {
209 hostProvider.hostVanished(host.id());
210 });
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700211 }
212
213 @Override
Hyunsun Moond02a5a72017-02-05 22:00:05 +0900214 public void removeInstance(HostId hostId) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700215 hostProvider.hostVanished(hostId);
216 }
217
Hyunsun Moon187bf532017-01-19 10:57:40 +0900218 private ServicePort getServicePortByPortName(String portName) {
219 Optional<ServicePort> sport = snetService.servicePorts()
220 .stream()
Hyunsun Moon5510e342017-02-23 19:41:00 +0900221 .filter(p -> Objects.equals(p.name(), portName))
Hyunsun Moon187bf532017-01-19 10:57:40 +0900222 .findFirst();
223 return sport.isPresent() ? sport.get() : null;
224 }
225
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700226 // TODO remove this when XOS provides access agent information
227 private boolean isAccessAgent(ConnectPoint connectPoint) {
228 Optional<AccessAgentData> agent = cordConfig.getAccessAgent(connectPoint.deviceId());
229 if (!agent.isPresent() || !agent.get().getVtnLocation().isPresent()) {
230 return false;
231 }
232 return agent.get().getVtnLocation().get().port().equals(connectPoint.port());
233 }
234
235 // TODO remove this when XOS provides access agent information
236 private void addAccessAgentInstance(ConnectPoint connectPoint) {
237 AccessAgentData agent = cordConfig.getAccessAgent(connectPoint.deviceId()).get();
238 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700239 .set(Instance.NETWORK_TYPE, ACCESS_AGENT.name())
240 .set(Instance.NETWORK_ID, NOT_APPLICABLE)
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700241 .set(Instance.PORT_ID, NOT_APPLICABLE)
242 .set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
243
244 HostDescription hostDesc = new DefaultHostDescription(
245 agent.getAgentMac(),
246 VlanId.NONE,
247 new HostLocation(connectPoint, System.currentTimeMillis()),
248 Sets.newHashSet(),
249 annotations.build());
250
251 HostId hostId = HostId.hostId(agent.getAgentMac());
252 hostProvider.hostDetected(hostId, hostDesc, false);
253 }
254
Hyunsun Moon5c143952016-10-19 18:34:46 -0700255 private Instance getInstance(PortId portId) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900256 // TODO use instance service instead
257 ServicePort sport = snetService.servicePort(portId);
258 if (sport == null) {
259 final String error = String.format(ERR_SERVICE_PORT, portId);
Hyunsun Moon5c143952016-10-19 18:34:46 -0700260 throw new IllegalStateException(error);
261 }
Hyunsun Moon187bf532017-01-19 10:57:40 +0900262 Host host = hostService.getHost(HostId.hostId(sport.mac()));
Hyunsun Moon5c143952016-10-19 18:34:46 -0700263 if (host == null) {
264 return null;
265 }
266 return Instance.of(host);
267 }
268
Hyunsun Moon187bf532017-01-19 10:57:40 +0900269 private class InternalServiceNetworkListener implements ServiceNetworkListener {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700270
271 @Override
Hyunsun Moon187bf532017-01-19 10:57:40 +0900272 public void event(ServiceNetworkEvent event) {
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900273 eventExecutor.execute(() -> {
274 NodeId leader = leadershipService.getLeader(appId.name());
275 if (!Objects.equals(localNodeId, leader)) {
276 // do not allow to proceed without leadership
277 return;
278 }
279 handle(event);
280 });
281 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700282
Jonathan Hart39960482017-11-20 15:50:36 -0800283 private boolean hasPort(Device device, String portName) {
284 return deviceService.getPorts(device.id()).stream()
285 .anyMatch(p -> p.annotations().value(PORT_NAME).equals(portName));
286 }
287
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900288 private void handle(ServiceNetworkEvent event) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700289 switch (event.type()) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900290 case SERVICE_PORT_CREATED:
291 case SERVICE_PORT_UPDATED:
292 log.debug("Processing service port {}", event.servicePort());
293 PortId portId = event.servicePort().id();
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900294 Instance instance = getInstance(portId);
Jonathan Hart39960482017-11-20 15:50:36 -0800295 if (instance == null) {
296 String portName = event.servicePort().name();
297
298 Optional<Device> device =
299 StreamSupport.stream(deviceService.getAvailableDevices().spliterator(), false)
300 .filter(d -> hasPort(d, portName))
301 .findAny();
302
303 Optional<Port> port = device.flatMap(d -> deviceService.getPorts(d.id()).stream()
304 .filter(p -> p.annotations().value(PORT_NAME) != null)
305 .filter(p -> p.annotations().value(PORT_NAME).equals(portName))
306 .findAny());
307
308 if (device.isPresent() && port.isPresent()) {
309 addInstance(new ConnectPoint(device.get().id(), port.get().number()));
310 }
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900311 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700312 break;
Hyunsun Moon187bf532017-01-19 10:57:40 +0900313 case SERVICE_PORT_REMOVED:
314 case SERVICE_NETWORK_CREATED:
315 case SERVICE_NETWORK_UPDATED:
316 case SERVICE_NETWORK_REMOVED:
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700317 default:
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700318 // do nothing for the other events
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700319 break;
320 }
321 }
322 }
323}