blob: aaa74e508fa61ae06a57d2f469c044b53c8cf936 [file] [log] [blame]
Hyunsun Moon187bf532017-01-19 10:57:40 +09001/*
2 * Copyright 2017-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.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";
80 private static final String ERR_NULL_SERVICE_PORT_NET_ID = "Service port network ID cannot be null";
81
82 private static final String ERR_NOT_FOUND = " does not exist";
83 private static final String ERR_IN_USE = " still in use";
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected NetworkConfigRegistry configRegistry;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected CoreService coreService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected HostService hostService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected ServiceNetworkStore snetStore;
96
97 // TODO add cordvtn config service and move this
98 private static final Class<CordVtnConfig> CONFIG_CLASS = CordVtnConfig.class;
99 private final ConfigFactory configFactory =
100 new ConfigFactory<ApplicationId, CordVtnConfig>(
101 SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "cordvtn") {
102 @Override
103 public CordVtnConfig createConfig() {
104 return new CordVtnConfig();
105 }
106 };
107
108 private final ServiceNetworkStoreDelegate delegate = new InternalServiceNetworkStoreDelegate();
109
110 @Activate
111 protected void activate() {
112 coreService.registerApplication(Constants.CORDVTN_APP_ID);
113 configRegistry.registerConfigFactory(configFactory);
114 snetStore.setDelegate(delegate);
115 log.info("Started");
116 }
117
118 @Deactivate
119 protected void deactivate() {
120 configRegistry.unregisterConfigFactory(configFactory);
121 snetStore.unsetDelegate(delegate);
122 log.info("Stopped");
123 }
124
125 @Override
126 public void purgeStates() {
127 snetStore.clear();
128 }
129
130 @Override
131 public ServiceNetwork serviceNetwork(NetworkId netId) {
132 checkNotNull(netId, ERR_NULL_SERVICE_NET_ID);
133 return snetStore.serviceNetwork(netId);
134 }
135
136 @Override
137 public Set<ServiceNetwork> serviceNetworks() {
138 return snetStore.serviceNetworks();
139 }
140
141 @Override
142 public void createServiceNetwork(ServiceNetwork snet) {
143 checkNotNull(snet, ERR_NULL_SERVICE_NET);
144 checkNotNull(snet.id(), ERR_NULL_SERVICE_NET_ID);
145 checkNotNull(snet.type(), ERR_NULL_SERVICE_NET_TYPE);
146 synchronized (this) {
147 snet.providers().keySet().forEach(provider -> {
148 if (snetStore.serviceNetwork(provider) == null) {
149 final String error = String.format(
150 MSG_PROVIDER_NET, provider.id(), ERR_NOT_FOUND);
151 throw new IllegalStateException(error);
152 }
153 });
154 snetStore.createServiceNetwork(snet);
155 log.info(String.format(MSG_SERVICE_NET, snet.name(), MSG_CREATED));
156 }
157 }
158
159 @Override
160 public void updateServiceNetwork(ServiceNetwork snet) {
161 checkNotNull(snet, ERR_NULL_SERVICE_NET);
162 checkNotNull(snet.id(), ERR_NULL_SERVICE_NET_ID);
163 synchronized (this) {
164 ServiceNetwork existing = snetStore.serviceNetwork(snet.id());
165 if (existing == null) {
166 final String error = String.format(
167 MSG_SERVICE_NET, snet.id(), ERR_NOT_FOUND);
168 throw new IllegalStateException(error);
169 }
170 // TODO do not allow service type update if the network in use
171 snetStore.updateServiceNetwork(DefaultServiceNetwork.builder(existing, snet).build());
172 log.info(String.format(MSG_SERVICE_NET, existing.name(), MSG_UPDATED));
173 }
174 }
175
176 @Override
177 public void removeServiceNetwork(NetworkId netId) {
178 checkNotNull(netId, ERR_NULL_SERVICE_NET_ID);
179 synchronized (this) {
180 if (isNetworkInUse(netId)) {
181 final String error = String.format(MSG_SERVICE_NET, netId, ERR_IN_USE);
182 throw new IllegalStateException(error);
183 }
184 // remove dependencies on this network first
185 serviceNetworks().stream().filter(n -> isProvider(n, netId)).forEach(n -> {
186 Map<NetworkId, DependencyType> newProviders = Maps.newHashMap(n.providers());
187 newProviders.remove(netId);
188 ServiceNetwork updated = DefaultServiceNetwork.builder(n)
189 .providers(newProviders)
190 .build();
191 snetStore.updateServiceNetwork(updated);
192 });
193 ServiceNetwork snet = snetStore.removeServiceNetwork(netId);
194 log.info(String.format(MSG_SERVICE_NET, snet.name(), MSG_REMOVED));
195 }
196 }
197
198 @Override
199 public ServicePort servicePort(PortId portId) {
200 checkNotNull(portId, ERR_NULL_SERVICE_PORT_ID);
201 return snetStore.servicePort(portId);
202 }
203
204 @Override
205 public Set<ServicePort> servicePorts() {
206 return snetStore.servicePorts();
207 }
208
209 @Override
210 public Set<ServicePort> servicePorts(NetworkId netId) {
211 Set<ServicePort> sports = snetStore.servicePorts().stream()
212 .filter(p -> Objects.equals(p.networkId(), netId))
213 .collect(Collectors.toSet());
214 return ImmutableSet.copyOf(sports);
215 }
216
217 @Override
218 public void createServicePort(ServicePort sport) {
219 checkNotNull(sport, ERR_NULL_SERVICE_PORT);
220 checkNotNull(sport.id(), ERR_NULL_SERVICE_PORT_ID);
221 checkNotNull(sport.networkId(), ERR_NULL_SERVICE_PORT_NET_ID);
222 synchronized (this) {
223 ServiceNetwork existing = snetStore.serviceNetwork(sport.networkId());
224 if (existing == null) {
225 final String error = String.format(
226 MSG_SERVICE_NET, sport.networkId(), ERR_NOT_FOUND);
227 throw new IllegalStateException(error);
228 }
229 snetStore.createServicePort(sport);
230 log.info(String.format(MSG_SERVICE_PORT, sport.id(), MSG_CREATED));
231 }
232 }
233
234 @Override
235 public void updateServicePort(ServicePort sport) {
236 checkNotNull(sport, ERR_NULL_SERVICE_PORT);
237 checkNotNull(sport.id(), ERR_NULL_SERVICE_PORT_ID);
238 synchronized (this) {
239 ServicePort existing = snetStore.servicePort(sport.id());
240 if (existing == null) {
241 final String error = String.format(
242 MSG_SERVICE_PORT, sport.id(), ERR_NOT_FOUND);
243 throw new IllegalStateException(error);
244 }
245 snetStore.updateServicePort(DefaultServicePort.builder(existing, sport).build());
246 log.info(String.format(MSG_SERVICE_PORT, sport.id(), MSG_UPDATED));
247 }
248 }
249
250 @Override
251 public void removeServicePort(PortId portId) {
252 checkNotNull(portId, ERR_NULL_SERVICE_PORT_ID);
253 synchronized (this) {
254 if (isPortInUse(portId)) {
255 final String error = String.format(MSG_SERVICE_PORT, portId, ERR_IN_USE);
256 throw new IllegalStateException(error);
257 }
258 snetStore.removeServicePort(portId);
259 log.info(String.format(MSG_SERVICE_PORT, portId, MSG_REMOVED));
260 }
261 }
262
263 /**
264 * Returns if the given target network is a provider of the given network.
265 *
266 * @param snet service network
267 * @param targetId target network
268 * @return true if the service network is a provider of the target network
269 */
270 private boolean isProvider(ServiceNetwork snet, NetworkId targetId) {
271 checkNotNull(snet);
272 return snet.providers().keySet().contains(targetId);
273 }
274
275 private boolean isNetworkInUse(NetworkId netId) {
276 // TODO use instance service to see if there's running instance for the network
277 return !servicePorts(netId).isEmpty();
278 }
279
280 private boolean isPortInUse(PortId portId) {
281 ServicePort sport = servicePort(portId);
282 if (sport == null) {
283 final String error = String.format(MSG_SERVICE_PORT, portId, ERR_NOT_FOUND);
284 throw new IllegalStateException(error);
285 }
286 // TODO use instance service to see if there's running instance for the port
287 Host host = hostService.getHost(HostId.hostId(sport.mac()));
288 return host != null;
289 }
290
291 private class InternalServiceNetworkStoreDelegate implements ServiceNetworkStoreDelegate {
292
293 @Override
294 public void notify(ServiceNetworkEvent event) {
295 if (event != null) {
296 log.trace("send service network event {}", event);
297 process(event);
298 }
299 }
300 }
301}