blob: 3bb305d86bff62cfe3e02a2bdec1c952ab363293 [file] [log] [blame]
Hyunsun Moon187bf532017-01-19 10:57:40 +09001/*
Brian O'Connor80dff972017-08-03 22:46:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moon187bf532017-01-19 10:57:40 +09003 *
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.ImmutableSet;
19import com.google.common.collect.Maps;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
28import org.onosproject.event.ListenerRegistry;
29import org.onosproject.net.Host;
30import org.onosproject.net.HostId;
31import org.onosproject.net.config.ConfigFactory;
32import org.onosproject.net.config.NetworkConfigRegistry;
33import org.onosproject.net.config.basics.SubjectFactories;
34import org.onosproject.net.host.HostService;
35import org.opencord.cordvtn.api.Constants;
36import org.opencord.cordvtn.api.CordVtnConfig;
37import org.opencord.cordvtn.api.core.ServiceNetworkAdminService;
38import org.opencord.cordvtn.api.core.ServiceNetworkEvent;
39import org.opencord.cordvtn.api.core.ServiceNetworkListener;
40import org.opencord.cordvtn.api.core.ServiceNetworkService;
41import org.opencord.cordvtn.api.core.ServiceNetworkStore;
42import org.opencord.cordvtn.api.core.ServiceNetworkStoreDelegate;
43import org.opencord.cordvtn.api.net.NetworkId;
44import org.opencord.cordvtn.api.net.PortId;
45import org.opencord.cordvtn.api.net.ServiceNetwork;
46import org.opencord.cordvtn.api.net.ServiceNetwork.DependencyType;
47import org.opencord.cordvtn.api.net.ServicePort;
48import org.slf4j.Logger;
49
50import java.util.Map;
51import java.util.Objects;
52import java.util.Set;
53import java.util.stream.Collectors;
54
55import static com.google.common.base.Preconditions.checkNotNull;
56import static org.slf4j.LoggerFactory.getLogger;
57
58/**
59 * Provides implementation of administering and interfacing service network and port.
60 */
61@Component(immediate = true)
62@Service
63public class ServiceNetworkManager extends ListenerRegistry<ServiceNetworkEvent, ServiceNetworkListener>
64 implements ServiceNetworkAdminService, ServiceNetworkService {
65
66 protected final Logger log = getLogger(getClass());
67
68 private static final String MSG_SERVICE_NET = "Service network %s %s";
69 private static final String MSG_SERVICE_PORT = "Service port %s %s";
70 private static final String MSG_PROVIDER_NET = "Provider network %s %s";
71 private static final String MSG_CREATED = "created";
72 private static final String MSG_UPDATED = "updated";
73 private static final String MSG_REMOVED = "removed";
74
75 private static final String ERR_NULL_SERVICE_NET = "Service network cannot be null";
76 private static final String ERR_NULL_SERVICE_NET_ID = "Service network ID cannot be null";
77 private static final String ERR_NULL_SERVICE_NET_TYPE = "Service network type cannot be null";
78 private static final String ERR_NULL_SERVICE_PORT = "Service port cannot be null";
79 private static final String ERR_NULL_SERVICE_PORT_ID = "Service port ID cannot be null";
Hyunsun Moon5510e342017-02-23 19:41:00 +090080 private static final String ERR_NULL_SERVICE_PORT_NAME = "Service port name cannot be null";
Hyunsun Moon187bf532017-01-19 10:57:40 +090081 private static final String ERR_NULL_SERVICE_PORT_NET_ID = "Service port network ID cannot be null";
82
83 private static final String ERR_NOT_FOUND = " does not exist";
84 private static final String ERR_IN_USE = " still in use";
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected NetworkConfigRegistry configRegistry;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected CoreService coreService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected HostService hostService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected ServiceNetworkStore snetStore;
97
98 // TODO add cordvtn config service and move this
99 private static final Class<CordVtnConfig> CONFIG_CLASS = CordVtnConfig.class;
100 private final ConfigFactory configFactory =
101 new ConfigFactory<ApplicationId, CordVtnConfig>(
102 SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "cordvtn") {
103 @Override
104 public CordVtnConfig createConfig() {
105 return new CordVtnConfig();
106 }
107 };
108
109 private final ServiceNetworkStoreDelegate delegate = new InternalServiceNetworkStoreDelegate();
110
111 @Activate
112 protected void activate() {
113 coreService.registerApplication(Constants.CORDVTN_APP_ID);
114 configRegistry.registerConfigFactory(configFactory);
115 snetStore.setDelegate(delegate);
116 log.info("Started");
117 }
118
119 @Deactivate
120 protected void deactivate() {
121 configRegistry.unregisterConfigFactory(configFactory);
122 snetStore.unsetDelegate(delegate);
123 log.info("Stopped");
124 }
125
126 @Override
127 public void purgeStates() {
128 snetStore.clear();
129 }
130
131 @Override
132 public ServiceNetwork serviceNetwork(NetworkId netId) {
133 checkNotNull(netId, ERR_NULL_SERVICE_NET_ID);
134 return snetStore.serviceNetwork(netId);
135 }
136
137 @Override
138 public Set<ServiceNetwork> serviceNetworks() {
139 return snetStore.serviceNetworks();
140 }
141
142 @Override
143 public void createServiceNetwork(ServiceNetwork snet) {
144 checkNotNull(snet, ERR_NULL_SERVICE_NET);
145 checkNotNull(snet.id(), ERR_NULL_SERVICE_NET_ID);
146 checkNotNull(snet.type(), ERR_NULL_SERVICE_NET_TYPE);
147 synchronized (this) {
148 snet.providers().keySet().forEach(provider -> {
149 if (snetStore.serviceNetwork(provider) == null) {
150 final String error = String.format(
151 MSG_PROVIDER_NET, provider.id(), ERR_NOT_FOUND);
152 throw new IllegalStateException(error);
153 }
154 });
155 snetStore.createServiceNetwork(snet);
156 log.info(String.format(MSG_SERVICE_NET, snet.name(), MSG_CREATED));
157 }
158 }
159
160 @Override
161 public void updateServiceNetwork(ServiceNetwork snet) {
162 checkNotNull(snet, ERR_NULL_SERVICE_NET);
163 checkNotNull(snet.id(), ERR_NULL_SERVICE_NET_ID);
164 synchronized (this) {
165 ServiceNetwork existing = snetStore.serviceNetwork(snet.id());
166 if (existing == null) {
167 final String error = String.format(
168 MSG_SERVICE_NET, snet.id(), ERR_NOT_FOUND);
169 throw new IllegalStateException(error);
170 }
171 // TODO do not allow service type update if the network in use
172 snetStore.updateServiceNetwork(DefaultServiceNetwork.builder(existing, snet).build());
173 log.info(String.format(MSG_SERVICE_NET, existing.name(), MSG_UPDATED));
174 }
175 }
176
177 @Override
178 public void removeServiceNetwork(NetworkId netId) {
179 checkNotNull(netId, ERR_NULL_SERVICE_NET_ID);
180 synchronized (this) {
181 if (isNetworkInUse(netId)) {
182 final String error = String.format(MSG_SERVICE_NET, netId, ERR_IN_USE);
183 throw new IllegalStateException(error);
184 }
185 // remove dependencies on this network first
186 serviceNetworks().stream().filter(n -> isProvider(n, netId)).forEach(n -> {
187 Map<NetworkId, DependencyType> newProviders = Maps.newHashMap(n.providers());
188 newProviders.remove(netId);
189 ServiceNetwork updated = DefaultServiceNetwork.builder(n)
190 .providers(newProviders)
191 .build();
192 snetStore.updateServiceNetwork(updated);
193 });
194 ServiceNetwork snet = snetStore.removeServiceNetwork(netId);
195 log.info(String.format(MSG_SERVICE_NET, snet.name(), MSG_REMOVED));
196 }
197 }
198
199 @Override
200 public ServicePort servicePort(PortId portId) {
201 checkNotNull(portId, ERR_NULL_SERVICE_PORT_ID);
202 return snetStore.servicePort(portId);
203 }
204
205 @Override
206 public Set<ServicePort> servicePorts() {
207 return snetStore.servicePorts();
208 }
209
210 @Override
211 public Set<ServicePort> servicePorts(NetworkId netId) {
212 Set<ServicePort> sports = snetStore.servicePorts().stream()
213 .filter(p -> Objects.equals(p.networkId(), netId))
214 .collect(Collectors.toSet());
215 return ImmutableSet.copyOf(sports);
216 }
217
218 @Override
219 public void createServicePort(ServicePort sport) {
220 checkNotNull(sport, ERR_NULL_SERVICE_PORT);
221 checkNotNull(sport.id(), ERR_NULL_SERVICE_PORT_ID);
Hyunsun Moon5510e342017-02-23 19:41:00 +0900222 checkNotNull(sport.id(), ERR_NULL_SERVICE_PORT_NAME);
Hyunsun Moon187bf532017-01-19 10:57:40 +0900223 checkNotNull(sport.networkId(), ERR_NULL_SERVICE_PORT_NET_ID);
224 synchronized (this) {
225 ServiceNetwork existing = snetStore.serviceNetwork(sport.networkId());
226 if (existing == null) {
227 final String error = String.format(
228 MSG_SERVICE_NET, sport.networkId(), ERR_NOT_FOUND);
229 throw new IllegalStateException(error);
230 }
231 snetStore.createServicePort(sport);
232 log.info(String.format(MSG_SERVICE_PORT, sport.id(), MSG_CREATED));
233 }
234 }
235
236 @Override
237 public void updateServicePort(ServicePort sport) {
238 checkNotNull(sport, ERR_NULL_SERVICE_PORT);
239 checkNotNull(sport.id(), ERR_NULL_SERVICE_PORT_ID);
240 synchronized (this) {
241 ServicePort existing = snetStore.servicePort(sport.id());
242 if (existing == null) {
243 final String error = String.format(
244 MSG_SERVICE_PORT, sport.id(), ERR_NOT_FOUND);
245 throw new IllegalStateException(error);
246 }
247 snetStore.updateServicePort(DefaultServicePort.builder(existing, sport).build());
248 log.info(String.format(MSG_SERVICE_PORT, sport.id(), MSG_UPDATED));
249 }
250 }
251
252 @Override
253 public void removeServicePort(PortId portId) {
254 checkNotNull(portId, ERR_NULL_SERVICE_PORT_ID);
255 synchronized (this) {
256 if (isPortInUse(portId)) {
257 final String error = String.format(MSG_SERVICE_PORT, portId, ERR_IN_USE);
258 throw new IllegalStateException(error);
259 }
260 snetStore.removeServicePort(portId);
261 log.info(String.format(MSG_SERVICE_PORT, portId, MSG_REMOVED));
262 }
263 }
264
265 /**
266 * Returns if the given target network is a provider of the given network.
267 *
268 * @param snet service network
269 * @param targetId target network
270 * @return true if the service network is a provider of the target network
271 */
272 private boolean isProvider(ServiceNetwork snet, NetworkId targetId) {
273 checkNotNull(snet);
274 return snet.providers().keySet().contains(targetId);
275 }
276
277 private boolean isNetworkInUse(NetworkId netId) {
278 // TODO use instance service to see if there's running instance for the network
279 return !servicePorts(netId).isEmpty();
280 }
281
282 private boolean isPortInUse(PortId portId) {
283 ServicePort sport = servicePort(portId);
284 if (sport == null) {
285 final String error = String.format(MSG_SERVICE_PORT, portId, ERR_NOT_FOUND);
286 throw new IllegalStateException(error);
287 }
288 // TODO use instance service to see if there's running instance for the port
289 Host host = hostService.getHost(HostId.hostId(sport.mac()));
290 return host != null;
291 }
292
293 private class InternalServiceNetworkStoreDelegate implements ServiceNetworkStoreDelegate {
294
295 @Override
296 public void notify(ServiceNetworkEvent event) {
297 if (event != null) {
298 log.trace("send service network event {}", event);
299 process(event);
300 }
301 }
302 }
303}