blob: 425f77d6c4769a6f55488071ed0afb0b409b0bff [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;
Yi Tsengf4e13e32017-03-30 15:38:39 -070019import org.onosproject.net.EncapsulationType;
20import org.onosproject.net.Host;
21import org.onosproject.net.host.HostEvent;
22import org.onosproject.net.host.HostListener;
23import org.onosproject.net.host.HostService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070024import org.onosproject.net.intf.Interface;
25import org.onosproject.net.intf.InterfaceService;
Yi Tsengf4e13e32017-03-30 15:38:39 -070026import org.onosproject.store.StoreDelegate;
Yi Tsengf4e13e32017-03-30 15:38:39 -070027import org.onosproject.vpls.api.Vpls;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070028import org.onosproject.vpls.api.VplsData;
29import org.onosproject.vpls.api.VplsOperation;
30import org.onosproject.vpls.api.VplsOperationService;
Yi Tsengf4e13e32017-03-30 15:38:39 -070031import org.onosproject.vpls.api.VplsStore;
32import org.onosproject.vpls.store.VplsStoreEvent;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070033import org.osgi.service.component.annotations.Activate;
34import org.osgi.service.component.annotations.Component;
35import org.osgi.service.component.annotations.Deactivate;
36import org.osgi.service.component.annotations.Reference;
37import org.osgi.service.component.annotations.ReferenceCardinality;
Yi Tsengf4e13e32017-03-30 15:38:39 -070038import org.slf4j.Logger;
39
40import java.util.Collection;
41import java.util.Set;
42
Ray Milkeyd84f89b2018-08-17 14:54:17 -070043import static java.util.Objects.requireNonNull;
Yi Tsengf4e13e32017-03-30 15:38:39 -070044import static org.slf4j.LoggerFactory.getLogger;
45
46/**
47 * Application to create L2 broadcast overlay networks using VLANs.
48 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070049@Component(immediate = true, service = Vpls.class)
Yi Tsengf4e13e32017-03-30 15:38:39 -070050public class VplsManager implements Vpls {
51 public static final String VPLS_APP = "org.onosproject.vpls";
52 private static final String UNSUPPORTED_STORE_EVENT_TYPE =
53 "Unsupported store event type {}.";
54 private final Logger log = getLogger(getClass());
55
Ray Milkeyd84f89b2018-08-17 14:54:17 -070056 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070057 protected HostService hostService;
58
Ray Milkeyd84f89b2018-08-17 14:54:17 -070059 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070060 protected InterfaceService interfaceService;
61
Ray Milkeyd84f89b2018-08-17 14:54:17 -070062 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070063 protected VplsStore vplsStore;
64
Ray Milkeyd84f89b2018-08-17 14:54:17 -070065 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070066 protected VplsOperationService operationService;
67
68 private StoreDelegate<VplsStoreEvent> vplsStoreDelegate;
69 private HostListener vplsHostListener;
70
71 @Activate
72 public void activate() {
73 vplsStoreDelegate = new VplsStoreDelegate();
74 vplsHostListener = new VplsHostListener();
75
76 vplsStore.setDelegate(vplsStoreDelegate);
77 hostService.addListener(vplsHostListener);
78 }
79
80 @Deactivate
81 public void deactivate() {
82 vplsStore.unsetDelegate(vplsStoreDelegate);
83 hostService.removeListener(vplsHostListener);
84 }
85
86 @Override
87 public VplsData createVpls(String vplsName, EncapsulationType encapsulationType) {
88 requireNonNull(vplsName);
89 requireNonNull(encapsulationType);
90
91 if (vplsStore.getVpls(vplsName) != null) {
92 return null;
93 }
94
95 VplsData vplsData = VplsData.of(vplsName, encapsulationType);
96 vplsStore.addVpls(vplsData);
97
98 return vplsData;
99 }
100
101 @Override
102 public VplsData removeVpls(VplsData vplsData) {
103 requireNonNull(vplsData);
Yi Tseng3069c612017-05-26 17:09:43 -0700104 VplsData newData = VplsData.of(vplsData);
105 newData.state(VplsData.VplsState.REMOVING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700106 vplsStore.removeVpls(vplsData);
107 return vplsData;
108 }
109
110 @Override
111 public void addInterfaces(VplsData vplsData, Collection<Interface> interfaces) {
112 requireNonNull(vplsData);
113 requireNonNull(interfaces);
Yi Tseng3069c612017-05-26 17:09:43 -0700114 VplsData newData = VplsData.of(vplsData);
115 newData.addInterfaces(interfaces);
116 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700117 }
118
119 @Override
120 public void addInterface(VplsData vplsData, Interface iface) {
121 requireNonNull(vplsData);
122 requireNonNull(iface);
Yi Tseng3069c612017-05-26 17:09:43 -0700123 VplsData newData = VplsData.of(vplsData);
124 newData.addInterface(iface);
125 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700126 }
127
128 @Override
129 public void setEncapsulationType(VplsData vplsData, EncapsulationType encapsulationType) {
130 requireNonNull(vplsData);
131 requireNonNull(encapsulationType);
Yi Tseng3069c612017-05-26 17:09:43 -0700132 VplsData newData = VplsData.of(vplsData);
133 if (newData.encapsulationType().equals(encapsulationType)) {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700134 // Encap type not changed.
135 return;
136 }
Yi Tseng3069c612017-05-26 17:09:43 -0700137 newData.encapsulationType(encapsulationType);
138 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700139 }
140
141 @Override
142 public VplsData getVpls(String vplsName) {
143 requireNonNull(vplsName);
144 return vplsStore.getVpls(vplsName);
145 }
146
147 @Override
148 public Collection<Interface> removeInterfaces(VplsData vplsData, Collection<Interface> interfaces) {
149 requireNonNull(vplsData);
150 requireNonNull(interfaces);
Yi Tseng3069c612017-05-26 17:09:43 -0700151 VplsData newData = VplsData.of(vplsData);
152 newData.removeInterfaces(interfaces);
153 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700154 return interfaces;
155 }
156
157 @Override
158 public Interface removeInterface(VplsData vplsData, Interface iface) {
159 requireNonNull(vplsData);
160 requireNonNull(iface);
Yi Tseng3069c612017-05-26 17:09:43 -0700161 VplsData newData = VplsData.of(vplsData);
162 newData.removeInterface(iface);
163 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700164 return iface;
165 }
166
167 @Override
168 public void removeAllVpls() {
169 Set<VplsData> allVplses = ImmutableSet.copyOf(vplsStore.getAllVpls());
170 allVplses.forEach(this::removeVpls);
171 }
172
173 @Override
174 public Collection<VplsData> getAllVpls() {
175 return ImmutableSet.copyOf(vplsStore.getAllVpls());
176 }
177
178 /**
179 * Updates VPLS status to the store.
180 *
181 * @param vplsData the VPLS
182 * @param vplsState the new state to the VPLS
183 */
184 private void updateVplsStatus(VplsData vplsData, VplsData.VplsState vplsState) {
185 vplsData.state(vplsState);
186 vplsStore.updateVpls(vplsData);
187 }
188
189 /**
190 * A listener for host events.
191 * Updates a VPLS if host added or removed.
192 */
193 class VplsHostListener implements HostListener {
194 @Override
195 public void event(HostEvent event) {
196 Host host = event.subject();
197 Interface iface = getHostInterface(host);
198 if (iface == null) {
199 return;
200 }
201 VplsData vplsData = vplsStore.getAllVpls().stream()
202 .filter(v -> v.interfaces().contains(iface))
203 .findFirst()
204 .orElse(null);
205 if (vplsData == null) {
206 // the host does not related to any vpls
207 return;
208 }
209 updateVplsStatus(vplsData, VplsData.VplsState.UPDATING);
210 }
211
212 /**
213 * Gets the network interface of the host.
214 *
215 * @param host the host
216 * @return the network interface of the host; null if no network
217 * interface found
218 */
219 private Interface getHostInterface(Host host) {
220 Set<Interface> interfaces = interfaceService.getInterfaces();
221 return interfaces.stream()
222 .filter(iface -> iface.connectPoint().equals(host.location()) &&
223 iface.vlan().equals(host.vlan()))
224 .findFirst()
225 .orElse(null);
226 }
227 }
228
229 /**
230 * Store delegate for VPLS store.
231 * Handles VPLS store event and generate VPLS operation according to event
232 * type.
233 */
234 class VplsStoreDelegate implements StoreDelegate<VplsStoreEvent> {
235
236 @Override
237 public void notify(VplsStoreEvent event) {
238 VplsOperation vplsOperation;
239 VplsOperation.Operation op;
240 VplsData vplsData = event.subject();
241 switch (event.type()) {
242 case ADD:
243 op = VplsOperation.Operation.ADD;
244 break;
245 case REMOVE:
246 op = VplsOperation.Operation.REMOVE;
247 break;
248 case UPDATE:
249 if (vplsData.state() == VplsData.VplsState.FAILED ||
250 vplsData.state() == VplsData.VplsState.ADDED ||
251 vplsData.state() == VplsData.VplsState.REMOVED) {
252 // Update the state only. Nothing to do if it is updated
253 // to ADDED, REMOVED or FAILED
254 op = null;
255 } else {
256 op = VplsOperation.Operation.UPDATE;
257 }
258 break;
259 default:
260 log.warn(UNSUPPORTED_STORE_EVENT_TYPE, event.type());
261 return;
262 }
263 if (op != null) {
264 vplsOperation = VplsOperation.of(vplsData, op);
265 operationService.submit(vplsOperation);
266 }
267 }
268 }
269}