blob: 6d5845761ba026138405c7b912b668222a223420 [file] [log] [blame]
Yi Tsengf4e13e32017-03-30 15:38:39 -07001/*
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.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;
27import org.onosproject.incubator.net.intf.Interface;
28import 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);
103 log.info("Stopped");
104 }
105
106 @Override
107 public void addVpls(VplsData vplsData) {
108 requireNonNull(vplsData);
109 if (vplsData.name().isEmpty()) {
110 throw new IllegalArgumentException("VPLS name is empty.");
111 }
112 vplsData.state(VplsData.VplsState.ADDING);
113 this.vplsDataStore.put(vplsData.name(), vplsData);
114 }
115
116 @Override
117 public void removeVpls(VplsData vplsData) {
118 requireNonNull(vplsData);
119 if (vplsData.name().isEmpty()) {
120 throw new IllegalArgumentException("VPLS name is empty.");
121 }
122 vplsData.state(VplsData.VplsState.REMOVING);
123 if (!this.vplsDataStore.containsKey(vplsData.name())) {
124 // notify the delegate asynchronously if VPLS does not exists
125 CompletableFuture.runAsync(() -> {
126 VplsStoreEvent event = new VplsStoreEvent(VplsStoreEvent.Type.REMOVE,
127 vplsData);
128 notifyDelegate(event);
129 });
130 return;
131 }
132 this.vplsDataStore.remove(vplsData.name());
133 }
134
135 @Override
136 public void updateVpls(VplsData vplsData) {
137 switch (vplsData.state()) {
138 case ADDED:
139 case REMOVED:
140 case FAILED:
141 // state update only
142 this.vplsDataStore.put(vplsData.name(), vplsData);
143 break;
144 default:
145 vplsData.state(VplsData.VplsState.UPDATING);
146 this.vplsDataStore.put(vplsData.name(), vplsData);
147 break;
148 }
149 }
150
151 @Override
152 public VplsData getVpls(String vplsName) {
153 return vplsDataStore.get(vplsName);
154 }
155
156 @Override
157 public Collection<VplsData> getAllVpls() {
158 return vplsDataStore.values();
159 }
160
161 /**
162 * Writes all VPLS data to the network configuration store.
163 *
164 * @param vplsDataCollection the VPLSs data
165 */
166 public void writeVplsToNetConfig(Collection<VplsData> vplsDataCollection) {
167 VplsAppConfig config = networkConfigService.addConfig(appId, VplsAppConfig.class);
Yi Tsengf31d2d92017-05-17 18:03:33 -0700168 if (config == null) {
169 log.debug("VPLS config is not available now");
170 return;
171 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700172 config.clearVplsConfig();
173
174 // Setup update time for this VPLS application configuration
175 WallClockTimestamp ts = new WallClockTimestamp();
176 config.updateTime(ts.unixTimestamp());
177
178 vplsDataCollection.forEach(vplsData -> {
179 Set<String> interfaceNames = vplsData.interfaces()
180 .stream()
181 .map(Interface::name)
182 .collect(Collectors.toSet());
183 VplsConfig vplsConfig = new VplsConfig(vplsData.name(), interfaceNames,
184 vplsData.encapsulationType());
185 config.addVpls(vplsConfig);
186 });
187
188 networkConfigService.applyConfig(appId, VplsAppConfig.class, config.node());
189 }
190
191 /**
192 * Listener for VPLS data store.
193 */
194 private class InternalVplsDataListener implements EventuallyConsistentMapListener<String, VplsData> {
195 private static final String STATE_UPDATE = "VPLS state updated, new VPLS: {}";
196
197 @Override
198 public void event(EventuallyConsistentMapEvent<String, VplsData> event) {
199 VplsData vplsData = event.value();
200 // Update network config
201 writeVplsToNetConfig(getAllVpls());
202 switch (event.type()) {
203 case PUT:
204 // Add or Update
205 if (vplsData.state() == VplsData.VplsState.ADDING) {
206 VplsStoreEvent vplsStoreEvent =
207 new VplsStoreEvent(VplsStoreEvent.Type.ADD, vplsData);
208 notifyDelegate(vplsStoreEvent);
209 } else if (vplsData.state() == VplsData.VplsState.UPDATING) {
210 VplsStoreEvent vplsStoreEvent =
211 new VplsStoreEvent(VplsStoreEvent.Type.UPDATE, vplsData);
212 notifyDelegate(vplsStoreEvent);
213 } else {
214 // Do nothing here, just update state from operation service
215 log.debug(STATE_UPDATE, vplsData);
216 }
217 break;
218 case REMOVE:
219 VplsStoreEvent vplsStoreEvent =
220 new VplsStoreEvent(VplsStoreEvent.Type.REMOVE, vplsData);
221 notifyDelegate(vplsStoreEvent);
222 break;
223 default:
224 break;
225 }
226
227 }
228 }
229}