blob: b31a575488b2ecce4aac20414a29919e2d2e7b4d [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) {
206 hostService.getConnectedHosts(connectPoint).stream()
207 .forEach(host -> {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700208 hostProvider.hostVanished(host.id());
209 });
210 }
211
212 @Override
Hyunsun Moond02a5a72017-02-05 22:00:05 +0900213 public void removeInstance(HostId hostId) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700214 hostProvider.hostVanished(hostId);
215 }
216
Hyunsun Moon187bf532017-01-19 10:57:40 +0900217 private ServicePort getServicePortByPortName(String portName) {
218 Optional<ServicePort> sport = snetService.servicePorts()
219 .stream()
220 .filter(p -> p.id().id().contains(portName.substring(3)))
221 .findFirst();
222 return sport.isPresent() ? sport.get() : null;
223 }
224
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700225 // TODO remove this when XOS provides access agent information
226 private boolean isAccessAgent(ConnectPoint connectPoint) {
227 Optional<AccessAgentData> agent = cordConfig.getAccessAgent(connectPoint.deviceId());
228 if (!agent.isPresent() || !agent.get().getVtnLocation().isPresent()) {
229 return false;
230 }
231 return agent.get().getVtnLocation().get().port().equals(connectPoint.port());
232 }
233
234 // TODO remove this when XOS provides access agent information
235 private void addAccessAgentInstance(ConnectPoint connectPoint) {
236 AccessAgentData agent = cordConfig.getAccessAgent(connectPoint.deviceId()).get();
237 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700238 .set(Instance.NETWORK_TYPE, ACCESS_AGENT.name())
239 .set(Instance.NETWORK_ID, NOT_APPLICABLE)
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700240 .set(Instance.PORT_ID, NOT_APPLICABLE)
241 .set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
242
243 HostDescription hostDesc = new DefaultHostDescription(
244 agent.getAgentMac(),
245 VlanId.NONE,
246 new HostLocation(connectPoint, System.currentTimeMillis()),
247 Sets.newHashSet(),
248 annotations.build());
249
250 HostId hostId = HostId.hostId(agent.getAgentMac());
251 hostProvider.hostDetected(hostId, hostDesc, false);
252 }
253
Hyunsun Moon5c143952016-10-19 18:34:46 -0700254 private Instance getInstance(PortId portId) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900255 // TODO use instance service instead
256 ServicePort sport = snetService.servicePort(portId);
257 if (sport == null) {
258 final String error = String.format(ERR_SERVICE_PORT, portId);
Hyunsun Moon5c143952016-10-19 18:34:46 -0700259 throw new IllegalStateException(error);
260 }
Hyunsun Moon187bf532017-01-19 10:57:40 +0900261 Host host = hostService.getHost(HostId.hostId(sport.mac()));
Hyunsun Moon5c143952016-10-19 18:34:46 -0700262 if (host == null) {
263 return null;
264 }
265 return Instance.of(host);
266 }
267
Hyunsun Moon187bf532017-01-19 10:57:40 +0900268 private class InternalServiceNetworkListener implements ServiceNetworkListener {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700269
270 @Override
Hyunsun Moon187bf532017-01-19 10:57:40 +0900271 public void event(ServiceNetworkEvent event) {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700272 NodeId leader = leadershipService.getLeader(appId.name());
273 if (!Objects.equals(localNodeId, leader)) {
274 // do not allow to proceed without leadership
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700275 return;
276 }
277
278 switch (event.type()) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900279 case SERVICE_PORT_CREATED:
280 case SERVICE_PORT_UPDATED:
281 log.debug("Processing service port {}", event.servicePort());
282 PortId portId = event.servicePort().id();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700283 eventExecutor.execute(() -> {
Hyunsun Moon5c143952016-10-19 18:34:46 -0700284 Instance instance = getInstance(portId);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700285 if (instance != null) {
286 addInstance(instance.host().location());
287 }
288 });
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700289 break;
Hyunsun Moon187bf532017-01-19 10:57:40 +0900290 case SERVICE_PORT_REMOVED:
291 case SERVICE_NETWORK_CREATED:
292 case SERVICE_NETWORK_UPDATED:
293 case SERVICE_NETWORK_REMOVED:
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700294 default:
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700295 // do nothing for the other events
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700296 break;
297 }
298 }
299 }
300}