blob: 4d68b8d1e19b1b2c49dd1354a9c57d0ce751ac1c [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;
48import org.opencord.cordvtn.api.core.CordVtnService;
49import org.opencord.cordvtn.api.instance.Instance;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070050import org.opencord.cordvtn.api.instance.InstanceService;
51import org.opencord.cordvtn.api.net.PortId;
52import org.opencord.cordvtn.api.net.VtnNetwork;
53import org.opencord.cordvtn.api.net.VtnNetworkEvent;
54import org.opencord.cordvtn.api.net.VtnNetworkListener;
55import org.opencord.cordvtn.api.net.VtnPort;
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 Moonfd5a24e2016-10-19 19:15:48 -070067import static org.opencord.cordvtn.api.net.ServiceNetwork.ServiceNetworkType.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 Mooneaf75e62016-09-27 16:40:23 -070079 private static final String ERR_VTN_NETWORK = "Faild to get VTN network for %s";
80 private static final String ERR_VTN_PORT = "Faild to get VTN 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)
105 protected CordVtnService vtnService;
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 Mooneaf75e62016-09-27 16:40:23 -0700109 private final VtnNetworkListener vtnNetListener = new InternalVtnNetworkListener();
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 Mooneaf75e62016-09-27 16:40:23 -0700129 vtnService.addListener(vtnNetListener);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700130
131 log.info("Started");
132 }
133
134 @Deactivate
135 protected void deactivate() {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700136 vtnService.removeListener(vtnNetListener);
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 Moon5c143952016-10-19 18:34:46 -0700167 VtnPort vtnPort = vtnService.vtnPort(port.annotations().value(PORT_NAME));
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700168 if (vtnPort == null) {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700169 log.warn(String.format(ERR_VTN_PORT, port));
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700170 return;
171 }
172
Hyunsun Moon5c143952016-10-19 18:34:46 -0700173 VtnNetwork vtnNet = vtnService.vtnNetwork(vtnPort.netId());
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700174 if (vtnNet == null) {
175 log.warn(String.format(ERR_VTN_NETWORK, vtnPort));
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700176 return;
177 }
178
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700179 // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
180 // existing instances.
181 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700182 .set(Instance.NETWORK_TYPE, vtnNet.type().name())
183 .set(Instance.NETWORK_ID, vtnNet.id().id())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700184 .set(Instance.PORT_ID, vtnPort.id().id())
185 .set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
186
187 HostDescription hostDesc = new DefaultHostDescription(
188 vtnPort.mac(),
189 VlanId.NONE,
190 new HostLocation(connectPoint, System.currentTimeMillis()),
191 Sets.newHashSet(vtnPort.ip()),
192 annotations.build());
193
194 HostId hostId = HostId.hostId(vtnPort.mac());
195 hostProvider.hostDetected(hostId, hostDesc, false);
196 }
197
198 @Override
199 public void addNestedInstance(HostId hostId, HostDescription description) {
200 DefaultAnnotations annotations = DefaultAnnotations.builder()
201 .set(Instance.NESTED_INSTANCE, Instance.TRUE)
202 .build();
203 annotations = annotations.merge(annotations, description.annotations());
204
205 HostDescription nestedHost = new DefaultHostDescription(
206 description.hwAddress(),
207 description.vlan(),
208 description.location(),
209 description.ipAddress(),
210 annotations);
211
212 hostProvider.hostDetected(hostId, nestedHost, false);
213 }
214
215 @Override
216 public void removeInstance(ConnectPoint connectPoint) {
217 hostService.getConnectedHosts(connectPoint).stream()
218 .forEach(host -> {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700219 hostProvider.hostVanished(host.id());
220 });
221 }
222
223 @Override
224 public void removeNestedInstance(HostId hostId) {
225 hostProvider.hostVanished(hostId);
226 }
227
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700228 // TODO remove this when XOS provides access agent information
229 private boolean isAccessAgent(ConnectPoint connectPoint) {
230 Optional<AccessAgentData> agent = cordConfig.getAccessAgent(connectPoint.deviceId());
231 if (!agent.isPresent() || !agent.get().getVtnLocation().isPresent()) {
232 return false;
233 }
234 return agent.get().getVtnLocation().get().port().equals(connectPoint.port());
235 }
236
237 // TODO remove this when XOS provides access agent information
238 private void addAccessAgentInstance(ConnectPoint connectPoint) {
239 AccessAgentData agent = cordConfig.getAccessAgent(connectPoint.deviceId()).get();
240 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700241 .set(Instance.NETWORK_TYPE, ACCESS_AGENT.name())
242 .set(Instance.NETWORK_ID, NOT_APPLICABLE)
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700243 .set(Instance.PORT_ID, NOT_APPLICABLE)
244 .set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
245
246 HostDescription hostDesc = new DefaultHostDescription(
247 agent.getAgentMac(),
248 VlanId.NONE,
249 new HostLocation(connectPoint, System.currentTimeMillis()),
250 Sets.newHashSet(),
251 annotations.build());
252
253 HostId hostId = HostId.hostId(agent.getAgentMac());
254 hostProvider.hostDetected(hostId, hostDesc, false);
255 }
256
Hyunsun Moon5c143952016-10-19 18:34:46 -0700257 private Instance getInstance(PortId portId) {
258 VtnPort vtnPort = vtnService.vtnPort(portId);
259 if (vtnPort == null) {
260 final String error = "Failed to build VTN port for " + portId.id();
261 throw new IllegalStateException(error);
262 }
263 Host host = hostService.getHost(HostId.hostId(vtnPort.mac()));
264 if (host == null) {
265 return null;
266 }
267 return Instance.of(host);
268 }
269
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700270 private class InternalVtnNetworkListener implements VtnNetworkListener {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700271
272 @Override
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700273 public void event(VtnNetworkEvent event) {
274 NodeId leader = leadershipService.getLeader(appId.name());
275 if (!Objects.equals(localNodeId, leader)) {
276 // do not allow to proceed without leadership
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700277 return;
278 }
279
280 switch (event.type()) {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700281 case VTN_PORT_CREATED:
282 case VTN_PORT_UPDATED:
283 log.debug("Processing service port {}", event.vtnPort());
284 PortId portId = event.vtnPort().id();
285 eventExecutor.execute(() -> {
Hyunsun Moon5c143952016-10-19 18:34:46 -0700286 Instance instance = getInstance(portId);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700287 if (instance != null) {
288 addInstance(instance.host().location());
289 }
290 });
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700291 break;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700292 case VTN_PORT_REMOVED:
293 case VTN_NETWORK_CREATED:
294 case VTN_NETWORK_UPDATED:
295 case VTN_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}