blob: 17300022e1118a16af6cd2e0a9085276da0dbb04 [file] [log] [blame]
Yi Tsengf4e13e32017-03-30 15:38:39 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Yi Tsengf4e13e32017-03-30 15:38:39 -07003 *
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.vpls.store;
17
Yi Tsengf4e13e32017-03-30 15:38:39 -070018import org.onlab.util.KryoNamespace;
19import org.onosproject.core.ApplicationId;
20import org.onosproject.core.CoreService;
Yi Tsengf4e13e32017-03-30 15:38:39 -070021import org.onosproject.net.config.NetworkConfigService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070022import org.onosproject.net.intf.Interface;
Yi Tsengf4e13e32017-03-30 15:38:39 -070023import org.onosproject.store.AbstractStore;
24import org.onosproject.store.StoreDelegate;
25import org.onosproject.store.serializers.KryoNamespaces;
26import org.onosproject.store.service.EventuallyConsistentMap;
27import org.onosproject.store.service.EventuallyConsistentMapEvent;
28import org.onosproject.store.service.EventuallyConsistentMapListener;
29import org.onosproject.store.service.StorageService;
30import org.onosproject.store.service.WallClockTimestamp;
31import org.onosproject.vpls.VplsManager;
32import org.onosproject.vpls.api.VplsData;
33import org.onosproject.vpls.api.VplsOperation;
Yi Tsengf4e13e32017-03-30 15:38:39 -070034import org.onosproject.vpls.api.VplsStore;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070035import org.onosproject.vpls.config.VplsAppConfig;
Yi Tsengf4e13e32017-03-30 15:38:39 -070036import org.onosproject.vpls.config.VplsConfig;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070037import org.osgi.service.component.annotations.Activate;
38import org.osgi.service.component.annotations.Component;
39import org.osgi.service.component.annotations.Deactivate;
40import org.osgi.service.component.annotations.Reference;
41import org.osgi.service.component.annotations.ReferenceCardinality;
Yi Tsengf4e13e32017-03-30 15:38:39 -070042import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44
45import java.util.Collection;
46import java.util.Set;
47import java.util.concurrent.CompletableFuture;
48import java.util.stream.Collectors;
49
Ray Milkeyd84f89b2018-08-17 14:54:17 -070050import static java.util.Objects.requireNonNull;
Yi Tsengf4e13e32017-03-30 15:38:39 -070051
52/**
53 * Implementation of VPLSConfigurationService which reads VPLS configuration
54 * from the network configuration service.
55 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070056@Component(immediate = true, service = VplsStore.class)
Yi Tsengf4e13e32017-03-30 15:38:39 -070057public class DistributedVplsStore
58 extends AbstractStore<VplsStoreEvent, StoreDelegate<VplsStoreEvent>>
59 implements VplsStore {
60
61 private static final KryoNamespace APP_KRYO = KryoNamespace.newBuilder()
62 .register(KryoNamespaces.API)
Yi Tsengf31d2d92017-05-17 18:03:33 -070063 .register(Interface.class)
Yi Tsengf4e13e32017-03-30 15:38:39 -070064 .register(VplsData.class)
Yi Tsengf31d2d92017-05-17 18:03:33 -070065 .register(VplsData.VplsState.class)
Yi Tsengf4e13e32017-03-30 15:38:39 -070066 .register(VplsOperation.class)
67 .build();
68
69 private final Logger log = LoggerFactory.getLogger(getClass());
70
Ray Milkeyd84f89b2018-08-17 14:54:17 -070071 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070072 protected CoreService coreService;
73
Ray Milkeyd84f89b2018-08-17 14:54:17 -070074 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070075 protected StorageService storageService;
76
Ray Milkeyd84f89b2018-08-17 14:54:17 -070077 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070078 protected NetworkConfigService networkConfigService;
79
80 private EventuallyConsistentMap<String, VplsData> vplsDataStore;
81 private EventuallyConsistentMapListener<String, VplsData> vplsDataListener;
82 private ApplicationId appId;
83
84 @Activate
85 protected void active() {
86 appId = coreService.registerApplication(VplsManager.VPLS_APP);
87
88 vplsDataStore = storageService.<String, VplsData>eventuallyConsistentMapBuilder()
89 .withName("VPLS-Data")
90 .withTimestampProvider((name, vpls) -> new WallClockTimestamp())
91 .withSerializer(APP_KRYO)
92 .build();
93 vplsDataListener = new InternalVplsDataListener();
94 vplsDataStore.addListener(vplsDataListener);
95 log.info("Started");
96 }
97
98 @Deactivate
99 protected void deactive() {
100 vplsDataStore.removeListener(vplsDataListener);
Yi Tsengada511f2017-05-18 14:46:04 -0700101 networkConfigService.removeConfig(appId);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700102 log.info("Stopped");
103 }
104
105 @Override
106 public void addVpls(VplsData vplsData) {
107 requireNonNull(vplsData);
108 if (vplsData.name().isEmpty()) {
109 throw new IllegalArgumentException("VPLS name is empty.");
110 }
111 vplsData.state(VplsData.VplsState.ADDING);
112 this.vplsDataStore.put(vplsData.name(), vplsData);
113 }
114
115 @Override
116 public void removeVpls(VplsData vplsData) {
117 requireNonNull(vplsData);
118 if (vplsData.name().isEmpty()) {
119 throw new IllegalArgumentException("VPLS name is empty.");
120 }
121 vplsData.state(VplsData.VplsState.REMOVING);
122 if (!this.vplsDataStore.containsKey(vplsData.name())) {
123 // notify the delegate asynchronously if VPLS does not exists
124 CompletableFuture.runAsync(() -> {
125 VplsStoreEvent event = new VplsStoreEvent(VplsStoreEvent.Type.REMOVE,
126 vplsData);
127 notifyDelegate(event);
128 });
129 return;
130 }
131 this.vplsDataStore.remove(vplsData.name());
132 }
133
134 @Override
135 public void updateVpls(VplsData vplsData) {
136 switch (vplsData.state()) {
137 case ADDED:
138 case REMOVED:
139 case FAILED:
140 // state update only
141 this.vplsDataStore.put(vplsData.name(), vplsData);
142 break;
143 default:
144 vplsData.state(VplsData.VplsState.UPDATING);
145 this.vplsDataStore.put(vplsData.name(), vplsData);
146 break;
147 }
148 }
149
150 @Override
151 public VplsData getVpls(String vplsName) {
152 return vplsDataStore.get(vplsName);
153 }
154
155 @Override
156 public Collection<VplsData> getAllVpls() {
157 return vplsDataStore.values();
158 }
159
160 /**
161 * Writes all VPLS data to the network configuration store.
162 *
163 * @param vplsDataCollection the VPLSs data
164 */
165 public void writeVplsToNetConfig(Collection<VplsData> vplsDataCollection) {
166 VplsAppConfig config = networkConfigService.addConfig(appId, VplsAppConfig.class);
Yi Tsengf31d2d92017-05-17 18:03:33 -0700167 if (config == null) {
168 log.debug("VPLS config is not available now");
169 return;
170 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700171 config.clearVplsConfig();
172
173 // Setup update time for this VPLS application configuration
174 WallClockTimestamp ts = new WallClockTimestamp();
175 config.updateTime(ts.unixTimestamp());
176
177 vplsDataCollection.forEach(vplsData -> {
178 Set<String> interfaceNames = vplsData.interfaces()
179 .stream()
180 .map(Interface::name)
181 .collect(Collectors.toSet());
182 VplsConfig vplsConfig = new VplsConfig(vplsData.name(), interfaceNames,
183 vplsData.encapsulationType());
184 config.addVpls(vplsConfig);
185 });
186
187 networkConfigService.applyConfig(appId, VplsAppConfig.class, config.node());
188 }
189
190 /**
191 * Listener for VPLS data store.
192 */
193 private class InternalVplsDataListener implements EventuallyConsistentMapListener<String, VplsData> {
194 private static final String STATE_UPDATE = "VPLS state updated, new VPLS: {}";
195
196 @Override
197 public void event(EventuallyConsistentMapEvent<String, VplsData> event) {
198 VplsData vplsData = event.value();
199 // Update network config
200 writeVplsToNetConfig(getAllVpls());
201 switch (event.type()) {
202 case PUT:
203 // Add or Update
204 if (vplsData.state() == VplsData.VplsState.ADDING) {
205 VplsStoreEvent vplsStoreEvent =
206 new VplsStoreEvent(VplsStoreEvent.Type.ADD, vplsData);
207 notifyDelegate(vplsStoreEvent);
208 } else if (vplsData.state() == VplsData.VplsState.UPDATING) {
209 VplsStoreEvent vplsStoreEvent =
210 new VplsStoreEvent(VplsStoreEvent.Type.UPDATE, vplsData);
211 notifyDelegate(vplsStoreEvent);
212 } else {
213 // Do nothing here, just update state from operation service
214 log.debug(STATE_UPDATE, vplsData);
215 }
216 break;
217 case REMOVE:
Yi Tseng3069c612017-05-26 17:09:43 -0700218 if (vplsData == null) {
219 vplsData = VplsData.of(event.key());
220 }
221 vplsData.state(VplsData.VplsState.REMOVING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700222 VplsStoreEvent vplsStoreEvent =
223 new VplsStoreEvent(VplsStoreEvent.Type.REMOVE, vplsData);
224 notifyDelegate(vplsStoreEvent);
225 break;
226 default:
227 break;
228 }
229
230 }
231 }
Ray Milkeyfacf2862017-08-03 11:58:29 -0700232}