blob: bd5e5287413a13374d8adac42d468cf07a50d3ea [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;
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;
33import org.onosproject.net.Host;
34import org.onosproject.net.HostId;
35import org.onosproject.net.HostLocation;
36import org.onosproject.net.Port;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070037import org.onosproject.net.device.DeviceService;
38import org.onosproject.net.host.DefaultHostDescription;
39import org.onosproject.net.host.HostDescription;
40import org.onosproject.net.host.HostProvider;
41import org.onosproject.net.host.HostProviderRegistry;
42import org.onosproject.net.host.HostProviderService;
43import org.onosproject.net.host.HostService;
44import org.onosproject.net.provider.AbstractProvider;
45import org.onosproject.net.provider.ProviderId;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080046import org.opencord.cordconfig.CordConfigService;
47import org.opencord.cordconfig.access.AccessAgentData;
Hyunsun Moon187bf532017-01-19 10:57:40 +090048import org.opencord.cordvtn.api.core.Instance;
49import org.opencord.cordvtn.api.core.InstanceService;
50import org.opencord.cordvtn.api.core.ServiceNetworkEvent;
51import org.opencord.cordvtn.api.core.ServiceNetworkListener;
52import org.opencord.cordvtn.api.core.ServiceNetworkService;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070053import org.opencord.cordvtn.api.net.PortId;
Hyunsun Moon187bf532017-01-19 10:57:40 +090054import org.opencord.cordvtn.api.net.ServiceNetwork;
55import org.opencord.cordvtn.api.net.ServicePort;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070056import org.slf4j.Logger;
57
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070058import java.util.Objects;
Hyunsun Moon1e88fef2016-08-04 14:00:35 -070059import java.util.Optional;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070060import java.util.concurrent.ExecutorService;
61
Hyunsun Moon537018f2016-07-27 18:51:00 -070062import static java.util.concurrent.Executors.newSingleThreadExecutor;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070063import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon81a13562016-08-04 13:48:08 -070064import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080065import static org.opencord.cordvtn.api.Constants.CORDVTN_APP_ID;
66import static org.opencord.cordvtn.api.Constants.NOT_APPLICABLE;
Hyunsun Moon187bf532017-01-19 10:57:40 +090067import static org.opencord.cordvtn.api.net.ServiceNetwork.NetworkType.ACCESS_AGENT;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070068import static org.slf4j.LoggerFactory.getLogger;
69
70/**
71 * Adds or removes instances to network services.
72 */
73@Component(immediate = true)
74@Service
75public class InstanceManager extends AbstractProvider implements HostProvider,
76 InstanceService {
77
78 protected final Logger log = getLogger(getClass());
Hyunsun Moon187bf532017-01-19 10:57:40 +090079 private static final String ERR_SERVICE_NETWORK = "Failed to get service network for %s";
80 private static final String ERR_SERVICE_PORT = "Failed to get service port for %s";
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070081
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070082 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected CoreService coreService;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070086 protected HostProviderRegistry hostProviderRegistry;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected DeviceService deviceService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected HostService hostService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070095 protected LeadershipService leadershipService;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070096
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070098 protected ClusterService clusterService;
99
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700100 // TODO get access agent container information from XOS
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected CordConfigService cordConfig;
103
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon187bf532017-01-19 10:57:40 +0900105 protected ServiceNetworkService snetService;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700106
107 private final ExecutorService eventExecutor =
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700108 newSingleThreadExecutor(groupedThreads(this.getClass().getSimpleName(), "event-handler"));
Hyunsun Moon187bf532017-01-19 10:57:40 +0900109 private final ServiceNetworkListener snetListener = new InternalServiceNetworkListener();
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700110
111 private ApplicationId appId;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700112 private NodeId localNodeId;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700113 private HostProviderService hostProvider;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700114
115 /**
116 * Creates an cordvtn host location provider.
117 */
118 public InstanceManager() {
119 super(new ProviderId("host", CORDVTN_APP_ID));
120 }
121
122 @Activate
123 protected void activate() {
124 appId = coreService.registerApplication(CORDVTN_APP_ID);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700125 localNodeId = clusterService.getLocalNode().id();
126 leadershipService.runForLeadership(appId.name());
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700127
128 hostProvider = hostProviderRegistry.register(this);
Hyunsun Moon187bf532017-01-19 10:57:40 +0900129 snetService.addListener(snetListener);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700130
131 log.info("Started");
132 }
133
134 @Deactivate
135 protected void deactivate() {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900136 snetService.removeListener(snetListener);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700137 hostProviderRegistry.unregister(this);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700138 eventExecutor.shutdown();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700139 leadershipService.withdraw(appId.name());
140
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700141 log.info("Stopped");
142 }
143
144 @Override
145 public void triggerProbe(Host host) {
146 /*
147 * Note: In CORD deployment, we assume that all hosts are configured.
148 * Therefore no probe is required.
149 */
150 }
151
152 @Override
153 public void addInstance(ConnectPoint connectPoint) {
154 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
155 if (port == null) {
156 log.debug("No port found from {}", connectPoint);
157 return;
158 }
159
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700160 // TODO remove this when XOS provides access agent information
161 // and handle it the same way wit the other instances
162 if (isAccessAgent(connectPoint)) {
163 addAccessAgentInstance(connectPoint);
164 return;
165 }
166
Hyunsun Moon187bf532017-01-19 10:57:40 +0900167 ServicePort sport = getServicePortByPortName(port.annotations().value(PORT_NAME));
168 if (sport == null) {
169 log.warn(String.format(ERR_SERVICE_PORT, port));
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700170 return;
171 }
172
Hyunsun Moon187bf532017-01-19 10:57:40 +0900173 ServiceNetwork snet = snetService.serviceNetwork(sport.networkId());
174 if (snet == null) {
175 final String error = String.format(ERR_SERVICE_NETWORK, sport);
176 throw new IllegalStateException(error);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700177 }
178
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700179 // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
Hyunsun Moon187bf532017-01-19 10:57:40 +0900180 // existing instances. Fix this after adding a method to update/reinstall
181 // flow rules for the existing service instances.
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700182 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Moon187bf532017-01-19 10:57:40 +0900183 .set(Instance.NETWORK_TYPE, snet.type().name())
184 .set(Instance.NETWORK_ID, snet.id().id())
185 .set(Instance.PORT_ID, sport.id().id())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700186 .set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
187
188 HostDescription hostDesc = new DefaultHostDescription(
Hyunsun Moon187bf532017-01-19 10:57:40 +0900189 sport.mac(),
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700190 VlanId.NONE,
191 new HostLocation(connectPoint, System.currentTimeMillis()),
Hyunsun Moon187bf532017-01-19 10:57:40 +0900192 Sets.newHashSet(sport.ip()),
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700193 annotations.build());
194
Hyunsun Moon187bf532017-01-19 10:57:40 +0900195 HostId hostId = HostId.hostId(sport.mac());
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700196 hostProvider.hostDetected(hostId, hostDesc, false);
197 }
198
199 @Override
Hyunsun Moond02a5a72017-02-05 22:00:05 +0900200 public void addInstance(HostId hostId, HostDescription description) {
201 hostProvider.hostDetected(hostId, description, false);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700202 }
203
204 @Override
205 public void removeInstance(ConnectPoint connectPoint) {
Hyunsun Moon851e57f2017-02-23 19:38:40 +0900206 hostService.getConnectedHosts(connectPoint).forEach(host -> {
207 hostProvider.hostVanished(host.id());
208 });
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700209 }
210
211 @Override
Hyunsun Moond02a5a72017-02-05 22:00:05 +0900212 public void removeInstance(HostId hostId) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700213 hostProvider.hostVanished(hostId);
214 }
215
Hyunsun Moon187bf532017-01-19 10:57:40 +0900216 private ServicePort getServicePortByPortName(String portName) {
217 Optional<ServicePort> sport = snetService.servicePorts()
218 .stream()
Hyunsun Moon5510e342017-02-23 19:41:00 +0900219 .filter(p -> Objects.equals(p.name(), portName))
Hyunsun Moon187bf532017-01-19 10:57:40 +0900220 .findFirst();
221 return sport.isPresent() ? sport.get() : null;
222 }
223
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700224 // TODO remove this when XOS provides access agent information
225 private boolean isAccessAgent(ConnectPoint connectPoint) {
226 Optional<AccessAgentData> agent = cordConfig.getAccessAgent(connectPoint.deviceId());
227 if (!agent.isPresent() || !agent.get().getVtnLocation().isPresent()) {
228 return false;
229 }
230 return agent.get().getVtnLocation().get().port().equals(connectPoint.port());
231 }
232
233 // TODO remove this when XOS provides access agent information
234 private void addAccessAgentInstance(ConnectPoint connectPoint) {
235 AccessAgentData agent = cordConfig.getAccessAgent(connectPoint.deviceId()).get();
236 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700237 .set(Instance.NETWORK_TYPE, ACCESS_AGENT.name())
238 .set(Instance.NETWORK_ID, NOT_APPLICABLE)
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700239 .set(Instance.PORT_ID, NOT_APPLICABLE)
240 .set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
241
242 HostDescription hostDesc = new DefaultHostDescription(
243 agent.getAgentMac(),
244 VlanId.NONE,
245 new HostLocation(connectPoint, System.currentTimeMillis()),
246 Sets.newHashSet(),
247 annotations.build());
248
249 HostId hostId = HostId.hostId(agent.getAgentMac());
250 hostProvider.hostDetected(hostId, hostDesc, false);
251 }
252
Hyunsun Moon5c143952016-10-19 18:34:46 -0700253 private Instance getInstance(PortId portId) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900254 // TODO use instance service instead
255 ServicePort sport = snetService.servicePort(portId);
256 if (sport == null) {
257 final String error = String.format(ERR_SERVICE_PORT, portId);
Hyunsun Moon5c143952016-10-19 18:34:46 -0700258 throw new IllegalStateException(error);
259 }
Hyunsun Moon187bf532017-01-19 10:57:40 +0900260 Host host = hostService.getHost(HostId.hostId(sport.mac()));
Hyunsun Moon5c143952016-10-19 18:34:46 -0700261 if (host == null) {
262 return null;
263 }
264 return Instance.of(host);
265 }
266
Hyunsun Moon187bf532017-01-19 10:57:40 +0900267 private class InternalServiceNetworkListener implements ServiceNetworkListener {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700268
269 @Override
Hyunsun Moon187bf532017-01-19 10:57:40 +0900270 public void event(ServiceNetworkEvent event) {
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900271 eventExecutor.execute(() -> {
272 NodeId leader = leadershipService.getLeader(appId.name());
273 if (!Objects.equals(localNodeId, leader)) {
274 // do not allow to proceed without leadership
275 return;
276 }
277 handle(event);
278 });
279 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700280
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900281 private void handle(ServiceNetworkEvent event) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700282 switch (event.type()) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900283 case SERVICE_PORT_CREATED:
284 case SERVICE_PORT_UPDATED:
285 log.debug("Processing service port {}", event.servicePort());
286 PortId portId = event.servicePort().id();
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900287 Instance instance = getInstance(portId);
288 if (instance != null) {
289 addInstance(instance.host().location());
290 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700291 break;
Hyunsun Moon187bf532017-01-19 10:57:40 +0900292 case SERVICE_PORT_REMOVED:
293 case SERVICE_NETWORK_CREATED:
294 case SERVICE_NETWORK_UPDATED:
295 case SERVICE_NETWORK_REMOVED:
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700296 default:
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700297 // do nothing for the other events
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700298 break;
299 }
300 }
301 }
302}