blob: 293f92b7c416ef036405f5e84b7c7b94a97c465d [file] [log] [blame]
Yi Tsengf4e13e32017-03-30 15:38:39 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-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;
17
18import com.google.common.collect.ImmutableSet;
DScano55a01032020-04-09 20:01:50 +020019import org.onosproject.codec.CodecService;
Yi Tsengf4e13e32017-03-30 15:38:39 -070020import org.onosproject.net.EncapsulationType;
21import org.onosproject.net.Host;
22import org.onosproject.net.host.HostEvent;
23import org.onosproject.net.host.HostListener;
24import org.onosproject.net.host.HostService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070025import org.onosproject.net.intf.Interface;
26import org.onosproject.net.intf.InterfaceService;
Yi Tsengf4e13e32017-03-30 15:38:39 -070027import org.onosproject.store.StoreDelegate;
Yi Tsengf4e13e32017-03-30 15:38:39 -070028import org.onosproject.vpls.api.Vpls;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070029import org.onosproject.vpls.api.VplsData;
30import org.onosproject.vpls.api.VplsOperation;
31import org.onosproject.vpls.api.VplsOperationService;
Yi Tsengf4e13e32017-03-30 15:38:39 -070032import org.onosproject.vpls.api.VplsStore;
DScano55a01032020-04-09 20:01:50 +020033import org.onosproject.vpls.rest.VplsCodec;
Yi Tsengf4e13e32017-03-30 15:38:39 -070034import org.onosproject.vpls.store.VplsStoreEvent;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070035import org.osgi.service.component.annotations.Activate;
36import org.osgi.service.component.annotations.Component;
37import org.osgi.service.component.annotations.Deactivate;
38import org.osgi.service.component.annotations.Reference;
39import org.osgi.service.component.annotations.ReferenceCardinality;
Yi Tsengf4e13e32017-03-30 15:38:39 -070040import org.slf4j.Logger;
41
42import java.util.Collection;
43import java.util.Set;
44
Ray Milkeyd84f89b2018-08-17 14:54:17 -070045import static java.util.Objects.requireNonNull;
Yi Tsengf4e13e32017-03-30 15:38:39 -070046import static org.slf4j.LoggerFactory.getLogger;
47
48/**
49 * Application to create L2 broadcast overlay networks using VLANs.
50 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070051@Component(immediate = true, service = Vpls.class)
Yi Tsengf4e13e32017-03-30 15:38:39 -070052public class VplsManager implements Vpls {
53 public static final String VPLS_APP = "org.onosproject.vpls";
54 private static final String UNSUPPORTED_STORE_EVENT_TYPE =
55 "Unsupported store event type {}.";
56 private final Logger log = getLogger(getClass());
57
Ray Milkeyd84f89b2018-08-17 14:54:17 -070058 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070059 protected HostService hostService;
60
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070062 protected InterfaceService interfaceService;
63
Ray Milkeyd84f89b2018-08-17 14:54:17 -070064 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070065 protected VplsStore vplsStore;
66
Ray Milkeyd84f89b2018-08-17 14:54:17 -070067 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070068 protected VplsOperationService operationService;
69
DScano55a01032020-04-09 20:01:50 +020070 @Reference(cardinality = ReferenceCardinality.MANDATORY)
71 protected CodecService codecService;
72
Yi Tsengf4e13e32017-03-30 15:38:39 -070073 private StoreDelegate<VplsStoreEvent> vplsStoreDelegate;
74 private HostListener vplsHostListener;
75
DScano55a01032020-04-09 20:01:50 +020076
Yi Tsengf4e13e32017-03-30 15:38:39 -070077 @Activate
78 public void activate() {
79 vplsStoreDelegate = new VplsStoreDelegate();
80 vplsHostListener = new VplsHostListener();
81
82 vplsStore.setDelegate(vplsStoreDelegate);
83 hostService.addListener(vplsHostListener);
DScano55a01032020-04-09 20:01:50 +020084 codecService.registerCodec(VplsData.class, new VplsCodec());
Yi Tsengf4e13e32017-03-30 15:38:39 -070085 }
86
87 @Deactivate
88 public void deactivate() {
89 vplsStore.unsetDelegate(vplsStoreDelegate);
90 hostService.removeListener(vplsHostListener);
DScano55a01032020-04-09 20:01:50 +020091 codecService.unregisterCodec(VplsData.class);
Yi Tsengf4e13e32017-03-30 15:38:39 -070092 }
93
94 @Override
95 public VplsData createVpls(String vplsName, EncapsulationType encapsulationType) {
96 requireNonNull(vplsName);
97 requireNonNull(encapsulationType);
98
99 if (vplsStore.getVpls(vplsName) != null) {
100 return null;
101 }
102
103 VplsData vplsData = VplsData.of(vplsName, encapsulationType);
104 vplsStore.addVpls(vplsData);
105
106 return vplsData;
107 }
108
109 @Override
110 public VplsData removeVpls(VplsData vplsData) {
111 requireNonNull(vplsData);
Yi Tseng3069c612017-05-26 17:09:43 -0700112 VplsData newData = VplsData.of(vplsData);
113 newData.state(VplsData.VplsState.REMOVING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700114 vplsStore.removeVpls(vplsData);
115 return vplsData;
116 }
117
118 @Override
119 public void addInterfaces(VplsData vplsData, Collection<Interface> interfaces) {
120 requireNonNull(vplsData);
121 requireNonNull(interfaces);
Yi Tseng3069c612017-05-26 17:09:43 -0700122 VplsData newData = VplsData.of(vplsData);
123 newData.addInterfaces(interfaces);
124 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700125 }
126
127 @Override
128 public void addInterface(VplsData vplsData, Interface iface) {
129 requireNonNull(vplsData);
130 requireNonNull(iface);
Yi Tseng3069c612017-05-26 17:09:43 -0700131 VplsData newData = VplsData.of(vplsData);
132 newData.addInterface(iface);
133 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700134 }
135
136 @Override
137 public void setEncapsulationType(VplsData vplsData, EncapsulationType encapsulationType) {
138 requireNonNull(vplsData);
139 requireNonNull(encapsulationType);
Yi Tseng3069c612017-05-26 17:09:43 -0700140 VplsData newData = VplsData.of(vplsData);
141 if (newData.encapsulationType().equals(encapsulationType)) {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700142 // Encap type not changed.
143 return;
144 }
Yi Tseng3069c612017-05-26 17:09:43 -0700145 newData.encapsulationType(encapsulationType);
146 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700147 }
148
149 @Override
150 public VplsData getVpls(String vplsName) {
151 requireNonNull(vplsName);
152 return vplsStore.getVpls(vplsName);
153 }
154
155 @Override
156 public Collection<Interface> removeInterfaces(VplsData vplsData, Collection<Interface> interfaces) {
157 requireNonNull(vplsData);
158 requireNonNull(interfaces);
Yi Tseng3069c612017-05-26 17:09:43 -0700159 VplsData newData = VplsData.of(vplsData);
160 newData.removeInterfaces(interfaces);
161 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700162 return interfaces;
163 }
164
165 @Override
166 public Interface removeInterface(VplsData vplsData, Interface iface) {
167 requireNonNull(vplsData);
168 requireNonNull(iface);
Yi Tseng3069c612017-05-26 17:09:43 -0700169 VplsData newData = VplsData.of(vplsData);
170 newData.removeInterface(iface);
171 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700172 return iface;
173 }
174
175 @Override
176 public void removeAllVpls() {
177 Set<VplsData> allVplses = ImmutableSet.copyOf(vplsStore.getAllVpls());
178 allVplses.forEach(this::removeVpls);
179 }
180
181 @Override
182 public Collection<VplsData> getAllVpls() {
183 return ImmutableSet.copyOf(vplsStore.getAllVpls());
184 }
185
186 /**
187 * Updates VPLS status to the store.
188 *
189 * @param vplsData the VPLS
190 * @param vplsState the new state to the VPLS
191 */
192 private void updateVplsStatus(VplsData vplsData, VplsData.VplsState vplsState) {
193 vplsData.state(vplsState);
194 vplsStore.updateVpls(vplsData);
195 }
196
197 /**
198 * A listener for host events.
199 * Updates a VPLS if host added or removed.
200 */
201 class VplsHostListener implements HostListener {
202 @Override
203 public void event(HostEvent event) {
204 Host host = event.subject();
205 Interface iface = getHostInterface(host);
206 if (iface == null) {
207 return;
208 }
209 VplsData vplsData = vplsStore.getAllVpls().stream()
210 .filter(v -> v.interfaces().contains(iface))
211 .findFirst()
212 .orElse(null);
213 if (vplsData == null) {
214 // the host does not related to any vpls
215 return;
216 }
217 updateVplsStatus(vplsData, VplsData.VplsState.UPDATING);
218 }
219
220 /**
221 * Gets the network interface of the host.
222 *
223 * @param host the host
224 * @return the network interface of the host; null if no network
225 * interface found
226 */
227 private Interface getHostInterface(Host host) {
228 Set<Interface> interfaces = interfaceService.getInterfaces();
229 return interfaces.stream()
230 .filter(iface -> iface.connectPoint().equals(host.location()) &&
231 iface.vlan().equals(host.vlan()))
232 .findFirst()
233 .orElse(null);
234 }
235 }
236
237 /**
238 * Store delegate for VPLS store.
239 * Handles VPLS store event and generate VPLS operation according to event
240 * type.
241 */
242 class VplsStoreDelegate implements StoreDelegate<VplsStoreEvent> {
243
244 @Override
245 public void notify(VplsStoreEvent event) {
246 VplsOperation vplsOperation;
247 VplsOperation.Operation op;
248 VplsData vplsData = event.subject();
249 switch (event.type()) {
250 case ADD:
251 op = VplsOperation.Operation.ADD;
252 break;
253 case REMOVE:
254 op = VplsOperation.Operation.REMOVE;
255 break;
256 case UPDATE:
257 if (vplsData.state() == VplsData.VplsState.FAILED ||
258 vplsData.state() == VplsData.VplsState.ADDED ||
259 vplsData.state() == VplsData.VplsState.REMOVED) {
260 // Update the state only. Nothing to do if it is updated
261 // to ADDED, REMOVED or FAILED
262 op = null;
263 } else {
264 op = VplsOperation.Operation.UPDATE;
265 }
266 break;
267 default:
268 log.warn(UNSUPPORTED_STORE_EVENT_TYPE, event.type());
269 return;
270 }
271 if (op != null) {
272 vplsOperation = VplsOperation.of(vplsData, op);
273 operationService.submit(vplsOperation);
274 }
275 }
276 }
277}