blob: ba35d9b2343b93aa158c0bdcf14243fe3cea2aa5 [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 Mooneaf75e62016-09-27 16:40:23 -070028import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.LeadershipService;
30import org.onosproject.cluster.NodeId;
Hyunsun Moon1e88fef2016-08-04 14:00:35 -070031import org.opencord.cordconfig.CordConfigService;
32import org.opencord.cordconfig.access.AccessAgentData;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070033import org.opencord.cordvtn.api.CordVtnService;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070034import org.opencord.cordvtn.api.Instance;
35import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
37import org.onosproject.dhcp.DhcpService;
38import org.onosproject.dhcp.IpAssignment;
39import org.onosproject.net.ConnectPoint;
40import org.onosproject.net.DefaultAnnotations;
41import org.onosproject.net.Host;
42import org.onosproject.net.HostId;
43import org.onosproject.net.HostLocation;
44import org.onosproject.net.Port;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070045import org.onosproject.net.device.DeviceService;
46import org.onosproject.net.host.DefaultHostDescription;
47import org.onosproject.net.host.HostDescription;
48import org.onosproject.net.host.HostProvider;
49import org.onosproject.net.host.HostProviderRegistry;
50import org.onosproject.net.host.HostProviderService;
51import org.onosproject.net.host.HostService;
52import org.onosproject.net.provider.AbstractProvider;
53import org.onosproject.net.provider.ProviderId;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070054import org.opencord.cordvtn.api.InstanceService;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070055import org.opencord.cordvtn.api.PortId;
56import org.opencord.cordvtn.api.VtnNetwork;
57import org.opencord.cordvtn.api.VtnNetworkEvent;
58import org.opencord.cordvtn.api.VtnNetworkListener;
59import org.opencord.cordvtn.api.VtnPort;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070060import org.slf4j.Logger;
61
62import java.util.Date;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070063import java.util.Objects;
Hyunsun Moon1e88fef2016-08-04 14:00:35 -070064import java.util.Optional;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070065import java.util.concurrent.ExecutorService;
66
Hyunsun Moon537018f2016-07-27 18:51:00 -070067import static java.util.concurrent.Executors.newSingleThreadExecutor;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070068import static org.onlab.util.Tools.groupedThreads;
69import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
Hyunsun Moon81a13562016-08-04 13:48:08 -070070import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070071import static org.opencord.cordvtn.api.Constants.*;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070072import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.ACCESS_AGENT;
73import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.MANAGEMENT_HOST;
74import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.MANAGEMENT_LOCAL;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070075import static org.slf4j.LoggerFactory.getLogger;
76
77/**
78 * Adds or removes instances to network services.
79 */
80@Component(immediate = true)
81@Service
82public class InstanceManager extends AbstractProvider implements HostProvider,
83 InstanceService {
84
85 protected final Logger log = getLogger(getClass());
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070086 private static final String ERR_VTN_NETWORK = "Faild to get VTN network for %s";
87 private static final String ERR_VTN_PORT = "Faild to get VTN port for %s";
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070088
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected CoreService coreService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070093 protected HostProviderRegistry hostProviderRegistry;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected DeviceService deviceService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected HostService hostService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700102 protected LeadershipService leadershipService;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700105 protected ClusterService clusterService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected DhcpService dhcpService;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700109
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700110 // TODO get access agent container information from XOS
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected CordConfigService cordConfig;
113
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected CordVtnService vtnService;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700116
117 private final ExecutorService eventExecutor =
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700118 newSingleThreadExecutor(groupedThreads(this.getClass().getSimpleName(), "event-handler"));
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700119 private final VtnNetworkListener vtnNetListener = new InternalVtnNetworkListener();
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700120
121 private ApplicationId appId;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700122 private NodeId localNodeId;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700123 private HostProviderService hostProvider;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700124
125 /**
126 * Creates an cordvtn host location provider.
127 */
128 public InstanceManager() {
129 super(new ProviderId("host", CORDVTN_APP_ID));
130 }
131
132 @Activate
133 protected void activate() {
134 appId = coreService.registerApplication(CORDVTN_APP_ID);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700135 localNodeId = clusterService.getLocalNode().id();
136 leadershipService.runForLeadership(appId.name());
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700137
138 hostProvider = hostProviderRegistry.register(this);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700139 vtnService.addListener(vtnNetListener);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700140
141 log.info("Started");
142 }
143
144 @Deactivate
145 protected void deactivate() {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700146 vtnService.removeListener(vtnNetListener);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700147 hostProviderRegistry.unregister(this);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700148 eventExecutor.shutdown();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700149 leadershipService.withdraw(appId.name());
150
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700151 log.info("Stopped");
152 }
153
154 @Override
155 public void triggerProbe(Host host) {
156 /*
157 * Note: In CORD deployment, we assume that all hosts are configured.
158 * Therefore no probe is required.
159 */
160 }
161
162 @Override
163 public void addInstance(ConnectPoint connectPoint) {
164 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
165 if (port == null) {
166 log.debug("No port found from {}", connectPoint);
167 return;
168 }
169
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700170 // TODO remove this when XOS provides access agent information
171 // and handle it the same way wit the other instances
172 if (isAccessAgent(connectPoint)) {
173 addAccessAgentInstance(connectPoint);
174 return;
175 }
176
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700177 VtnPort vtnPort = vtnService.getVtnPort(port.annotations().value(PORT_NAME));
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700178 if (vtnPort == null) {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700179 log.warn(String.format(ERR_VTN_PORT, port));
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700180 return;
181 }
182
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700183 VtnNetwork vtnNet = vtnService.getVtnNetworkOrDefault(vtnPort.netId());
184 if (vtnNet == null) {
185 log.warn(String.format(ERR_VTN_NETWORK, vtnPort));
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700186 return;
187 }
188
189 // register DHCP lease for the new instance
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700190 registerDhcpLease(vtnPort.mac(), vtnPort.ip().getIp4Address(), vtnNet);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700191
192 // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
193 // existing instances.
194 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700195 .set(Instance.NETWORK_TYPE, vtnNet.type().name())
196 .set(Instance.NETWORK_ID, vtnNet.id().id())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700197 .set(Instance.PORT_ID, vtnPort.id().id())
198 .set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
199
200 HostDescription hostDesc = new DefaultHostDescription(
201 vtnPort.mac(),
202 VlanId.NONE,
203 new HostLocation(connectPoint, System.currentTimeMillis()),
204 Sets.newHashSet(vtnPort.ip()),
205 annotations.build());
206
207 HostId hostId = HostId.hostId(vtnPort.mac());
208 hostProvider.hostDetected(hostId, hostDesc, false);
209 }
210
211 @Override
212 public void addNestedInstance(HostId hostId, HostDescription description) {
213 DefaultAnnotations annotations = DefaultAnnotations.builder()
214 .set(Instance.NESTED_INSTANCE, Instance.TRUE)
215 .build();
216 annotations = annotations.merge(annotations, description.annotations());
217
218 HostDescription nestedHost = new DefaultHostDescription(
219 description.hwAddress(),
220 description.vlan(),
221 description.location(),
222 description.ipAddress(),
223 annotations);
224
225 hostProvider.hostDetected(hostId, nestedHost, false);
226 }
227
228 @Override
229 public void removeInstance(ConnectPoint connectPoint) {
230 hostService.getConnectedHosts(connectPoint).stream()
231 .forEach(host -> {
232 dhcpService.removeStaticMapping(host.mac());
233 hostProvider.hostVanished(host.id());
234 });
235 }
236
237 @Override
238 public void removeNestedInstance(HostId hostId) {
239 hostProvider.hostVanished(hostId);
240 }
241
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700242 private void registerDhcpLease(MacAddress macAddr, Ip4Address ipAddr, VtnNetwork vtnNet) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700243 Ip4Address broadcast = Ip4Address.makeMaskedAddress(
244 ipAddr,
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700245 vtnNet.subnet().prefixLength());
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700246
247 IpAssignment.Builder ipBuilder = IpAssignment.builder()
248 .ipAddress(ipAddr)
249 .leasePeriod(DHCP_INFINITE_LEASE)
250 .timestamp(new Date())
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700251 .subnetMask(Ip4Address.makeMaskPrefix(vtnNet.subnet().prefixLength()))
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700252 .broadcast(broadcast)
253 .domainServer(DEFAULT_DNS)
254 .assignmentStatus(Option_RangeNotEnforced);
255
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700256 if (vtnNet.type() != MANAGEMENT_HOST && vtnNet.type() != MANAGEMENT_LOCAL) {
257 ipBuilder = ipBuilder.routerAddress(vtnNet.serviceIp().getIp4Address());
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700258 }
259
260 log.debug("Set static DHCP mapping for {} {}", macAddr, ipAddr);
261 dhcpService.setStaticMapping(macAddr, ipBuilder.build());
262 }
263
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700264 // TODO remove this when XOS provides access agent information
265 private boolean isAccessAgent(ConnectPoint connectPoint) {
266 Optional<AccessAgentData> agent = cordConfig.getAccessAgent(connectPoint.deviceId());
267 if (!agent.isPresent() || !agent.get().getVtnLocation().isPresent()) {
268 return false;
269 }
270 return agent.get().getVtnLocation().get().port().equals(connectPoint.port());
271 }
272
273 // TODO remove this when XOS provides access agent information
274 private void addAccessAgentInstance(ConnectPoint connectPoint) {
275 AccessAgentData agent = cordConfig.getAccessAgent(connectPoint.deviceId()).get();
276 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700277 .set(Instance.NETWORK_TYPE, ACCESS_AGENT.name())
278 .set(Instance.NETWORK_ID, NOT_APPLICABLE)
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700279 .set(Instance.PORT_ID, NOT_APPLICABLE)
280 .set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
281
282 HostDescription hostDesc = new DefaultHostDescription(
283 agent.getAgentMac(),
284 VlanId.NONE,
285 new HostLocation(connectPoint, System.currentTimeMillis()),
286 Sets.newHashSet(),
287 annotations.build());
288
289 HostId hostId = HostId.hostId(agent.getAgentMac());
290 hostProvider.hostDetected(hostId, hostDesc, false);
291 }
292
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700293 private class InternalVtnNetworkListener implements VtnNetworkListener {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700294
295 @Override
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700296 public void event(VtnNetworkEvent event) {
297 NodeId leader = leadershipService.getLeader(appId.name());
298 if (!Objects.equals(localNodeId, leader)) {
299 // do not allow to proceed without leadership
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700300 return;
301 }
302
303 switch (event.type()) {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700304 case VTN_PORT_CREATED:
305 case VTN_PORT_UPDATED:
306 log.debug("Processing service port {}", event.vtnPort());
307 PortId portId = event.vtnPort().id();
308 eventExecutor.execute(() -> {
309 Instance instance = vtnService.getInstance(portId);
310 if (instance != null) {
311 addInstance(instance.host().location());
312 }
313 });
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700314 break;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700315 case VTN_PORT_REMOVED:
316 case VTN_NETWORK_CREATED:
317 case VTN_NETWORK_UPDATED:
318 case VTN_NETWORK_REMOVED:
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700319 default:
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700320 // do nothing for the other events
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700321 break;
322 }
323 }
324 }
325}