blob: 4125399cb0472cf7874a61c200a80196d0fb3786 [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
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.apache.felix.scr.annotations.Service;
24import org.onlab.util.KryoNamespace;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070027import org.onosproject.net.intf.Interface;
Yi Tsengf4e13e32017-03-30 15:38:39 -070028import org.onosproject.net.config.NetworkConfigService;
29import org.onosproject.store.AbstractStore;
30import org.onosproject.store.StoreDelegate;
31import org.onosproject.store.serializers.KryoNamespaces;
32import org.onosproject.store.service.EventuallyConsistentMap;
33import org.onosproject.store.service.EventuallyConsistentMapEvent;
34import org.onosproject.store.service.EventuallyConsistentMapListener;
35import org.onosproject.store.service.StorageService;
36import org.onosproject.store.service.WallClockTimestamp;
37import org.onosproject.vpls.VplsManager;
38import org.onosproject.vpls.api.VplsData;
39import org.onosproject.vpls.api.VplsOperation;
40import org.onosproject.vpls.config.VplsAppConfig;
41import org.onosproject.vpls.api.VplsStore;
42import org.onosproject.vpls.config.VplsConfig;
43import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
45
46import java.util.Collection;
47import java.util.Set;
48import java.util.concurrent.CompletableFuture;
49import java.util.stream.Collectors;
50
51import static java.util.Objects.*;
52
53/**
54 * Implementation of VPLSConfigurationService which reads VPLS configuration
55 * from the network configuration service.
56 */
57@Component(immediate = true)
58@Service
59public class DistributedVplsStore
60 extends AbstractStore<VplsStoreEvent, StoreDelegate<VplsStoreEvent>>
61 implements VplsStore {
62
63 private static final KryoNamespace APP_KRYO = KryoNamespace.newBuilder()
64 .register(KryoNamespaces.API)
Yi Tsengf31d2d92017-05-17 18:03:33 -070065 .register(Interface.class)
Yi Tsengf4e13e32017-03-30 15:38:39 -070066 .register(VplsData.class)
Yi Tsengf31d2d92017-05-17 18:03:33 -070067 .register(VplsData.VplsState.class)
Yi Tsengf4e13e32017-03-30 15:38:39 -070068 .register(VplsOperation.class)
69 .build();
70
71 private final Logger log = LoggerFactory.getLogger(getClass());
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected CoreService coreService;
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected StorageService storageService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected NetworkConfigService networkConfigService;
81
82 private EventuallyConsistentMap<String, VplsData> vplsDataStore;
83 private EventuallyConsistentMapListener<String, VplsData> vplsDataListener;
84 private ApplicationId appId;
85
86 @Activate
87 protected void active() {
88 appId = coreService.registerApplication(VplsManager.VPLS_APP);
89
90 vplsDataStore = storageService.<String, VplsData>eventuallyConsistentMapBuilder()
91 .withName("VPLS-Data")
92 .withTimestampProvider((name, vpls) -> new WallClockTimestamp())
93 .withSerializer(APP_KRYO)
94 .build();
95 vplsDataListener = new InternalVplsDataListener();
96 vplsDataStore.addListener(vplsDataListener);
97 log.info("Started");
98 }
99
100 @Deactivate
101 protected void deactive() {
102 vplsDataStore.removeListener(vplsDataListener);
Yi Tsengada511f2017-05-18 14:46:04 -0700103 networkConfigService.removeConfig(appId);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700104 log.info("Stopped");
105 }
106
107 @Override
108 public void addVpls(VplsData vplsData) {
109 requireNonNull(vplsData);
110 if (vplsData.name().isEmpty()) {
111 throw new IllegalArgumentException("VPLS name is empty.");
112 }
113 vplsData.state(VplsData.VplsState.ADDING);
114 this.vplsDataStore.put(vplsData.name(), vplsData);
115 }
116
117 @Override
118 public void removeVpls(VplsData vplsData) {
119 requireNonNull(vplsData);
120 if (vplsData.name().isEmpty()) {
121 throw new IllegalArgumentException("VPLS name is empty.");
122 }
123 vplsData.state(VplsData.VplsState.REMOVING);
124 if (!this.vplsDataStore.containsKey(vplsData.name())) {
125 // notify the delegate asynchronously if VPLS does not exists
126 CompletableFuture.runAsync(() -> {
127 VplsStoreEvent event = new VplsStoreEvent(VplsStoreEvent.Type.REMOVE,
128 vplsData);
129 notifyDelegate(event);
130 });
131 return;
132 }
133 this.vplsDataStore.remove(vplsData.name());
134 }
135
136 @Override
137 public void updateVpls(VplsData vplsData) {
138 switch (vplsData.state()) {
139 case ADDED:
140 case REMOVED:
141 case FAILED:
142 // state update only
143 this.vplsDataStore.put(vplsData.name(), vplsData);
144 break;
145 default:
146 vplsData.state(VplsData.VplsState.UPDATING);
147 this.vplsDataStore.put(vplsData.name(), vplsData);
148 break;
149 }
150 }
151
152 @Override
153 public VplsData getVpls(String vplsName) {
154 return vplsDataStore.get(vplsName);
155 }
156
157 @Override
158 public Collection<VplsData> getAllVpls() {
159 return vplsDataStore.values();
160 }
161
162 /**
163 * Writes all VPLS data to the network configuration store.
164 *
165 * @param vplsDataCollection the VPLSs data
166 */
167 public void writeVplsToNetConfig(Collection<VplsData> vplsDataCollection) {
168 VplsAppConfig config = networkConfigService.addConfig(appId, VplsAppConfig.class);
Yi Tsengf31d2d92017-05-17 18:03:33 -0700169 if (config == null) {
170 log.debug("VPLS config is not available now");
171 return;
172 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700173 config.clearVplsConfig();
174
175 // Setup update time for this VPLS application configuration
176 WallClockTimestamp ts = new WallClockTimestamp();
177 config.updateTime(ts.unixTimestamp());
178
179 vplsDataCollection.forEach(vplsData -> {
180 Set<String> interfaceNames = vplsData.interfaces()
181 .stream()
182 .map(Interface::name)
183 .collect(Collectors.toSet());
184 VplsConfig vplsConfig = new VplsConfig(vplsData.name(), interfaceNames,
185 vplsData.encapsulationType());
186 config.addVpls(vplsConfig);
187 });
188
189 networkConfigService.applyConfig(appId, VplsAppConfig.class, config.node());
190 }
191
192 /**
193 * Listener for VPLS data store.
194 */
195 private class InternalVplsDataListener implements EventuallyConsistentMapListener<String, VplsData> {
196 private static final String STATE_UPDATE = "VPLS state updated, new VPLS: {}";
197
198 @Override
199 public void event(EventuallyConsistentMapEvent<String, VplsData> event) {
200 VplsData vplsData = event.value();
201 // Update network config
202 writeVplsToNetConfig(getAllVpls());
203 switch (event.type()) {
204 case PUT:
205 // Add or Update
206 if (vplsData.state() == VplsData.VplsState.ADDING) {
207 VplsStoreEvent vplsStoreEvent =
208 new VplsStoreEvent(VplsStoreEvent.Type.ADD, vplsData);
209 notifyDelegate(vplsStoreEvent);
210 } else if (vplsData.state() == VplsData.VplsState.UPDATING) {
211 VplsStoreEvent vplsStoreEvent =
212 new VplsStoreEvent(VplsStoreEvent.Type.UPDATE, vplsData);
213 notifyDelegate(vplsStoreEvent);
214 } else {
215 // Do nothing here, just update state from operation service
216 log.debug(STATE_UPDATE, vplsData);
217 }
218 break;
219 case REMOVE:
Yi Tseng3069c612017-05-26 17:09:43 -0700220 if (vplsData == null) {
221 vplsData = VplsData.of(event.key());
222 }
223 vplsData.state(VplsData.VplsState.REMOVING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700224 VplsStoreEvent vplsStoreEvent =
225 new VplsStoreEvent(VplsStoreEvent.Type.REMOVE, vplsData);
226 notifyDelegate(vplsStoreEvent);
227 break;
228 default:
229 break;
230 }
231
232 }
233 }
Ray Milkeyfacf2862017-08-03 11:58:29 -0700234}