blob: 626d2ebe638e9c5a0c18d7471f51433aeef1e6be [file] [log] [blame]
Jian Li810f58c2021-02-27 01:10:50 +09001/*
2 * Copyright 2021-present Open Networking Foundation
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.onosproject.kubevirtnetworking.impl;
17
Jian Li073f1ba2021-02-28 03:50:15 +090018import com.google.common.base.Strings;
Jian Li810f58c2021-02-27 01:10:50 +090019import com.google.common.collect.ImmutableSet;
20import org.onlab.util.KryoNamespace;
21import org.onosproject.core.ApplicationId;
22import org.onosproject.core.CoreService;
Jian Li073f1ba2021-02-28 03:50:15 +090023import org.onosproject.kubevirtnetworking.api.DefaultKubevirtFloatingIp;
Jian Li810f58c2021-02-27 01:10:50 +090024import org.onosproject.kubevirtnetworking.api.DefaultKubevirtRouter;
Jian Li073f1ba2021-02-28 03:50:15 +090025import org.onosproject.kubevirtnetworking.api.KubevirtFloatingIp;
Jian Li810f58c2021-02-27 01:10:50 +090026import org.onosproject.kubevirtnetworking.api.KubevirtPeerRouter;
27import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
28import org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent;
29import org.onosproject.kubevirtnetworking.api.KubevirtRouterStore;
30import org.onosproject.kubevirtnetworking.api.KubevirtRouterStoreDelegate;
31import org.onosproject.store.AbstractStore;
32import org.onosproject.store.serializers.KryoNamespaces;
33import org.onosproject.store.service.ConsistentMap;
34import org.onosproject.store.service.MapEvent;
35import org.onosproject.store.service.MapEventListener;
36import org.onosproject.store.service.Serializer;
37import org.onosproject.store.service.StorageService;
38import org.onosproject.store.service.Versioned;
39import org.osgi.service.component.annotations.Activate;
40import org.osgi.service.component.annotations.Component;
41import org.osgi.service.component.annotations.Deactivate;
42import org.osgi.service.component.annotations.Reference;
43import org.osgi.service.component.annotations.ReferenceCardinality;
44import org.slf4j.Logger;
45
46import java.util.Collection;
Jian Lib636f702021-03-03 14:46:50 +090047import java.util.HashSet;
Daniel Park2884b232021-03-04 18:58:47 +090048import java.util.Objects;
Jian Li810f58c2021-02-27 01:10:50 +090049import java.util.Set;
50import java.util.concurrent.ExecutorService;
51
52import static com.google.common.base.Preconditions.checkArgument;
53import static java.util.concurrent.Executors.newSingleThreadExecutor;
54import static org.onlab.util.Tools.groupedThreads;
Jian Li073f1ba2021-02-28 03:50:15 +090055import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_ASSOCIATED;
56import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_CREATED;
57import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_DISASSOCIATED;
58import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_REMOVED;
59import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_UPDATED;
Daniel Park2884b232021-03-04 18:58:47 +090060import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_GATEWAY_NODE_ATTACHED;
61import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_GATEWAY_NODE_CHANGED;
62import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_GATEWAY_NODE_DETACHED;
Jian Li810f58c2021-02-27 01:10:50 +090063import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_CREATED;
Jian Lib636f702021-03-03 14:46:50 +090064import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED;
65import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED;
66import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED;
67import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED;
Jian Li810f58c2021-02-27 01:10:50 +090068import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_REMOVED;
69import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_UPDATED;
Daniel Park8ad7c3b2021-04-09 15:45:59 +090070import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_SNAT_STATUS_DISABLED;
Jian Li810f58c2021-02-27 01:10:50 +090071import static org.slf4j.LoggerFactory.getLogger;
72
73/**
74 * Implementation of kubevirt router store using consistent map.
75 */
76@Component(immediate = true, service = KubevirtRouterStore.class)
77public class DistributedKubevirtRouterStore
78 extends AbstractStore<KubevirtRouterEvent, KubevirtRouterStoreDelegate>
79 implements KubevirtRouterStore {
80
81 private final Logger log = getLogger(getClass());
82
83 private static final String ERR_NOT_FOUND = " does not exist";
84 private static final String ERR_DUPLICATE = " already exists";
Jian Lib636f702021-03-03 14:46:50 +090085 private static final String MSG_FLOATING_IP = "Kubevirt floating IP %s %s with %s";
86 private static final String MSG_ASSOCIATED = "associated";
87 private static final String MSG_DISASSOCIATED = "disassociated";
88
Jian Li810f58c2021-02-27 01:10:50 +090089 private static final String APP_ID = "org.onosproject.kubevirtnetwork";
90
91 private static final KryoNamespace
92 SERIALIZER_KUBEVIRT_ROUTER = KryoNamespace.newBuilder()
93 .register(KryoNamespaces.API)
94 .register(KubevirtRouter.class)
95 .register(DefaultKubevirtRouter.class)
96 .register(KubevirtPeerRouter.class)
Jian Li073f1ba2021-02-28 03:50:15 +090097 .register(KubevirtFloatingIp.class)
98 .register(DefaultKubevirtFloatingIp.class)
Jian Li810f58c2021-02-27 01:10:50 +090099 .register(Collection.class)
100 .build();
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY)
103 protected CoreService coreService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY)
106 protected StorageService storageService;
107
108 private final ExecutorService eventExecutor = newSingleThreadExecutor(
109 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
110
111 private final MapEventListener<String, KubevirtRouter> routerMapListener =
112 new KubevirtRouterMapListener();
Jian Li073f1ba2021-02-28 03:50:15 +0900113 private final MapEventListener<String, KubevirtFloatingIp> fipMapListener =
114 new KubevirtFloatingIpMapListener();
Jian Li810f58c2021-02-27 01:10:50 +0900115
116 private ConsistentMap<String, KubevirtRouter> routerStore;
Jian Li073f1ba2021-02-28 03:50:15 +0900117 private ConsistentMap<String, KubevirtFloatingIp> fipStore;
Jian Li810f58c2021-02-27 01:10:50 +0900118
119 @Activate
120 protected void activate() {
121 ApplicationId appId = coreService.registerApplication(APP_ID);
122 routerStore = storageService.<String, KubevirtRouter>consistentMapBuilder()
123 .withSerializer(Serializer.using(SERIALIZER_KUBEVIRT_ROUTER))
124 .withName("kubevirt-routerstore")
125 .withApplicationId(appId)
126 .build();
Jian Li073f1ba2021-02-28 03:50:15 +0900127 fipStore = storageService.<String, KubevirtFloatingIp>consistentMapBuilder()
128 .withSerializer(Serializer.using(SERIALIZER_KUBEVIRT_ROUTER))
129 .withName("kubevirt-fipstore")
130 .withApplicationId(appId)
131 .build();
Jian Li810f58c2021-02-27 01:10:50 +0900132 routerStore.addListener(routerMapListener);
Jian Li073f1ba2021-02-28 03:50:15 +0900133 fipStore.addListener(fipMapListener);
Jian Li810f58c2021-02-27 01:10:50 +0900134 log.info("Started");
135 }
136
137 @Deactivate
138 protected void deactivate() {
139 routerStore.removeListener(routerMapListener);
Jian Li073f1ba2021-02-28 03:50:15 +0900140 fipStore.removeListener(fipMapListener);
Jian Li810f58c2021-02-27 01:10:50 +0900141 eventExecutor.shutdown();
142 log.info("Stopped");
143 }
144
145 @Override
146 public void createRouter(KubevirtRouter router) {
147 routerStore.compute(router.name(), (name, existing) -> {
148 final String error = router.name() + ERR_DUPLICATE;
149 checkArgument(existing == null, error);
150 return router;
151 });
152 }
153
154 @Override
155 public void updateRouter(KubevirtRouter router) {
156 routerStore.compute(router.name(), (name, existing) -> {
157 final String error = router.name() + ERR_NOT_FOUND;
158 checkArgument(existing != null, error);
159 return router;
160 });
161 }
162
163 @Override
164 public KubevirtRouter removeRouter(String name) {
165 Versioned<KubevirtRouter> router = routerStore.remove(name);
166 if (router == null) {
167 final String error = name + ERR_NOT_FOUND;
168 throw new IllegalArgumentException(error);
169 }
170 return router.value();
171 }
172
173 @Override
174 public KubevirtRouter router(String name) {
175 return routerStore.asJavaMap().get(name);
176 }
177
178 @Override
179 public Set<KubevirtRouter> routers() {
180 return ImmutableSet.copyOf(routerStore.asJavaMap().values());
181 }
182
183 @Override
Jian Li073f1ba2021-02-28 03:50:15 +0900184 public void createFloatingIp(KubevirtFloatingIp floatingIp) {
185 fipStore.compute(floatingIp.id(), (id, existing) -> {
186 final String error = floatingIp.id() + ERR_DUPLICATE;
187 checkArgument(existing == null, error);
188 return floatingIp;
189 });
190 }
191
192 @Override
193 public void updateFloatingIp(KubevirtFloatingIp floatingIp) {
194 fipStore.compute(floatingIp.id(), (id, existing) -> {
195 final String error = floatingIp.id() + ERR_NOT_FOUND;
196 checkArgument(existing != null, error);
197 return floatingIp;
198 });
199 }
200
201 @Override
202 public KubevirtFloatingIp removeFloatingIp(String id) {
203 Versioned<KubevirtFloatingIp> floatingIp = fipStore.remove(id);
204 if (floatingIp == null) {
205 final String error = id + ERR_NOT_FOUND;
206 throw new IllegalArgumentException(error);
207 }
208 return floatingIp.value();
209 }
210
211 @Override
212 public KubevirtFloatingIp floatingIp(String id) {
213 return fipStore.asJavaMap().get(id);
214 }
215
216 @Override
217 public Set<KubevirtFloatingIp> floatingIps() {
218 return ImmutableSet.copyOf(fipStore.asJavaMap().values());
219 }
220
221
222 @Override
Jian Li810f58c2021-02-27 01:10:50 +0900223 public void clear() {
224 routerStore.clear();
Jian Li073f1ba2021-02-28 03:50:15 +0900225 fipStore.clear();
Jian Li810f58c2021-02-27 01:10:50 +0900226 }
227
228 private class KubevirtRouterMapListener implements MapEventListener<String, KubevirtRouter> {
229
230 @Override
231 public void event(MapEvent<String, KubevirtRouter> event) {
232 switch (event.type()) {
233 case INSERT:
234 log.debug("Kubevirt router created");
235 eventExecutor.execute(() ->
236 notifyDelegate(new KubevirtRouterEvent(
237 KUBEVIRT_ROUTER_CREATED, event.newValue().value())));
238 break;
239 case UPDATE:
Jian Lib636f702021-03-03 14:46:50 +0900240 eventExecutor.execute(() -> processRouterMapUpdate(event));
Jian Li810f58c2021-02-27 01:10:50 +0900241 break;
242 case REMOVE:
243 log.debug("Kubevirt router removed");
244 eventExecutor.execute(() ->
245 notifyDelegate(new KubevirtRouterEvent(
246 KUBEVIRT_ROUTER_REMOVED, event.oldValue().value())));
247 break;
248 default:
249 // do nothing
250 break;
251 }
252 }
Jian Lib636f702021-03-03 14:46:50 +0900253
254 private void processRouterMapUpdate(MapEvent<String, KubevirtRouter> event) {
255 log.debug("Kubevirt router updated");
256 eventExecutor.execute(() ->
257 notifyDelegate(new KubevirtRouterEvent(
258 KUBEVIRT_ROUTER_UPDATED, event.newValue().value())));
259
260 KubevirtRouter router = Strings.isNullOrEmpty(
261 event.newValue().value().name()) ?
262 null :
263 router(event.newValue().value().name());
264
265 KubevirtRouter oldValue = event.oldValue().value();
266 KubevirtRouter newValue = event.newValue().value();
267
268 if (oldValue.external().size() == 0 && newValue.external().size() > 0) {
269 newValue.external().entrySet().stream().findAny()
270 .ifPresent(entry ->
271 notifyDelegate(new KubevirtRouterEvent(
272 KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED,
273 router, entry.getKey(), entry.getValue(),
Daniel Park5a3e9392021-03-23 08:00:00 +0900274 newValue.peerRouter().ipAddress().toString(),
275 newValue.peerRouter().macAddress())));
Jian Lib636f702021-03-03 14:46:50 +0900276 }
277
278 if (oldValue.external().size() > 0 && newValue.external().size() == 0) {
279 oldValue.external().entrySet().stream().findAny()
280 .ifPresent(entry ->
281 notifyDelegate(new KubevirtRouterEvent(
282 KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED,
283 router, entry.getKey(), entry.getValue(),
Daniel Park5a3e9392021-03-23 08:00:00 +0900284 oldValue.peerRouter().ipAddress().toString(),
285 oldValue.peerRouter().macAddress())));
Jian Lib636f702021-03-03 14:46:50 +0900286 }
287
288 Set<String> added = new HashSet<>(newValue.internal());
289 Set<String> oldset = oldValue.internal();
290 added.removeAll(oldset);
291
292 Set<String> removed = new HashSet<>(oldValue.internal());
293 Set<String> newset = newValue.internal();
294 removed.removeAll(newset);
295
296 if (added.size() > 0) {
297 notifyDelegate(new KubevirtRouterEvent(
298 KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED,
299 router, added));
300 }
301
302 if (removed.size() > 0) {
303 notifyDelegate(new KubevirtRouterEvent(
304 KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED,
305 router, removed));
306 }
Daniel Park2884b232021-03-04 18:58:47 +0900307 if (oldValue.electedGateway() == null
308 && newValue.electedGateway() != null) {
309 notifyDelegate(new KubevirtRouterEvent(
310 KUBEVIRT_GATEWAY_NODE_ATTACHED,
311 router, newValue.electedGateway()));
312 }
313
314 if (oldValue.electedGateway() != null
315 && newValue.electedGateway() == null) {
316 notifyDelegate(new KubevirtRouterEvent(
317 KUBEVIRT_GATEWAY_NODE_DETACHED,
318 router, oldValue.electedGateway()));
319 }
320
321 if (oldValue.electedGateway() != null
322 && newValue.electedGateway() != null
323 && !Objects.equals(oldValue.electedGateway(), newValue.electedGateway())) {
324 notifyDelegate(new KubevirtRouterEvent(
325 KUBEVIRT_GATEWAY_NODE_CHANGED,
326 router, oldValue.electedGateway()));
327 }
Daniel Park8ad7c3b2021-04-09 15:45:59 +0900328
329 if (oldValue.enableSnat() && !newValue.enableSnat()) {
330 notifyDelegate(new KubevirtRouterEvent(
331 KUBEVIRT_SNAT_STATUS_DISABLED, router));
332 }
Jian Lib636f702021-03-03 14:46:50 +0900333 }
Jian Li810f58c2021-02-27 01:10:50 +0900334 }
Jian Li073f1ba2021-02-28 03:50:15 +0900335
336 private class KubevirtFloatingIpMapListener implements MapEventListener<String, KubevirtFloatingIp> {
337
338 @Override
339 public void event(MapEvent<String, KubevirtFloatingIp> event) {
340 switch (event.type()) {
341 case INSERT:
342 eventExecutor.execute(() -> processFloatingIpMapInsertion(event));
343 break;
344 case UPDATE:
345 eventExecutor.execute(() -> processFloatingIpMapUpdate(event));
346 break;
347 case REMOVE:
348 eventExecutor.execute(() -> processFloatingIpMapRemoval(event));
349 break;
350 default:
351 break;
352 }
353 }
354
355 private void processFloatingIpMapInsertion(MapEvent<String, KubevirtFloatingIp> event) {
356 log.debug("Kubevirt floating IP created");
357 KubevirtRouter router = Strings.isNullOrEmpty(
358 event.newValue().value().routerName()) ?
359 null :
360 router(event.newValue().value().routerName());
361 notifyDelegate(new KubevirtRouterEvent(
362 KUBEVIRT_FLOATING_IP_CREATED,
363 router,
364 event.newValue().value()));
365 }
366
367 private void processFloatingIpMapUpdate(MapEvent<String, KubevirtFloatingIp> event) {
368 log.debug("Kubevirt floating IP updated");
369 KubevirtRouter router = Strings.isNullOrEmpty(
370 event.newValue().value().routerName()) ?
371 null :
372 router(event.newValue().value().routerName());
373 notifyDelegate(new KubevirtRouterEvent(
374 KUBEVIRT_FLOATING_IP_UPDATED,
375 router,
376 event.newValue().value()));
377 processFloatingIpUpdate(event, router);
378 }
379
380 private void processFloatingIpMapRemoval(MapEvent<String, KubevirtFloatingIp> event) {
381 log.debug("Kubevirt floating IP removed");
382 KubevirtRouter router = Strings.isNullOrEmpty(
383 event.oldValue().value().routerName()) ?
384 null :
385 router(event.oldValue().value().routerName());
386 notifyDelegate(new KubevirtRouterEvent(
387 KUBEVIRT_FLOATING_IP_REMOVED,
388 router,
389 event.oldValue().value()));
390 }
391
392 private void processFloatingIpUpdate(MapEvent<String, KubevirtFloatingIp> event,
393 KubevirtRouter router) {
394 String oldPodName = event.oldValue().value().podName();
395 String newPodName = event.newValue().value().podName();
396
397 if (Strings.isNullOrEmpty(oldPodName) && !Strings.isNullOrEmpty(newPodName)) {
398 notifyDelegate(new KubevirtRouterEvent(
399 KUBEVIRT_FLOATING_IP_ASSOCIATED,
400 router,
401 event.newValue().value(), newPodName));
Jian Lib636f702021-03-03 14:46:50 +0900402 log.info(String.format(MSG_FLOATING_IP,
403 event.newValue().value().floatingIp(), MSG_ASSOCIATED, newPodName));
Jian Li073f1ba2021-02-28 03:50:15 +0900404 }
405
406 if (!Strings.isNullOrEmpty(oldPodName) && Strings.isNullOrEmpty(newPodName)) {
407 notifyDelegate(new KubevirtRouterEvent(
408 KUBEVIRT_FLOATING_IP_DISASSOCIATED,
409 router,
Daniel Parkf3136042021-03-10 07:49:11 +0900410 event.oldValue().value(), oldPodName));
Jian Lib636f702021-03-03 14:46:50 +0900411 log.info(String.format(MSG_FLOATING_IP,
412 event.newValue().value().floatingIp(), MSG_DISASSOCIATED, oldPodName));
Jian Li073f1ba2021-02-28 03:50:15 +0900413 }
414 }
415 }
Jian Li810f58c2021-02-27 01:10:50 +0900416}