blob: 1955ced0e93e24695708fd9c908a8c4efb856b0c [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;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
25import org.onosproject.incubator.net.intf.Interface;
26import org.onosproject.incubator.net.intf.InterfaceService;
27import org.onosproject.net.EncapsulationType;
28import org.onosproject.net.Host;
29import org.onosproject.net.host.HostEvent;
30import org.onosproject.net.host.HostListener;
31import org.onosproject.net.host.HostService;
32import org.onosproject.store.StoreDelegate;
33import org.onosproject.vpls.api.VplsData;
34import org.onosproject.vpls.api.VplsOperationService;
35import org.onosproject.vpls.api.VplsOperation;
36import org.onosproject.vpls.api.Vpls;
37import org.onosproject.vpls.api.VplsStore;
38import org.onosproject.vpls.store.VplsStoreEvent;
39import org.slf4j.Logger;
40
41import java.util.Collection;
42import java.util.Set;
43
44import static java.util.Objects.*;
45import static org.slf4j.LoggerFactory.getLogger;
46
47/**
48 * Application to create L2 broadcast overlay networks using VLANs.
49 */
50@Component(immediate = true)
51@Service
52public 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
58 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 protected HostService hostService;
60
61 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 protected InterfaceService interfaceService;
63
64 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 protected VplsStore vplsStore;
66
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected VplsOperationService operationService;
69
70 private StoreDelegate<VplsStoreEvent> vplsStoreDelegate;
71 private HostListener vplsHostListener;
72
73 @Activate
74 public void activate() {
75 vplsStoreDelegate = new VplsStoreDelegate();
76 vplsHostListener = new VplsHostListener();
77
78 vplsStore.setDelegate(vplsStoreDelegate);
79 hostService.addListener(vplsHostListener);
80 }
81
82 @Deactivate
83 public void deactivate() {
84 vplsStore.unsetDelegate(vplsStoreDelegate);
85 hostService.removeListener(vplsHostListener);
86 }
87
88 @Override
89 public VplsData createVpls(String vplsName, EncapsulationType encapsulationType) {
90 requireNonNull(vplsName);
91 requireNonNull(encapsulationType);
92
93 if (vplsStore.getVpls(vplsName) != null) {
94 return null;
95 }
96
97 VplsData vplsData = VplsData.of(vplsName, encapsulationType);
98 vplsStore.addVpls(vplsData);
99
100 return vplsData;
101 }
102
103 @Override
104 public VplsData removeVpls(VplsData vplsData) {
105 requireNonNull(vplsData);
Yi Tseng3069c612017-05-26 17:09:43 -0700106 VplsData newData = VplsData.of(vplsData);
107 newData.state(VplsData.VplsState.REMOVING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700108 vplsStore.removeVpls(vplsData);
109 return vplsData;
110 }
111
112 @Override
113 public void addInterfaces(VplsData vplsData, Collection<Interface> interfaces) {
114 requireNonNull(vplsData);
115 requireNonNull(interfaces);
Yi Tseng3069c612017-05-26 17:09:43 -0700116 VplsData newData = VplsData.of(vplsData);
117 newData.addInterfaces(interfaces);
118 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700119 }
120
121 @Override
122 public void addInterface(VplsData vplsData, Interface iface) {
123 requireNonNull(vplsData);
124 requireNonNull(iface);
Yi Tseng3069c612017-05-26 17:09:43 -0700125 VplsData newData = VplsData.of(vplsData);
126 newData.addInterface(iface);
127 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700128 }
129
130 @Override
131 public void setEncapsulationType(VplsData vplsData, EncapsulationType encapsulationType) {
132 requireNonNull(vplsData);
133 requireNonNull(encapsulationType);
Yi Tseng3069c612017-05-26 17:09:43 -0700134 VplsData newData = VplsData.of(vplsData);
135 if (newData.encapsulationType().equals(encapsulationType)) {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700136 // Encap type not changed.
137 return;
138 }
Yi Tseng3069c612017-05-26 17:09:43 -0700139 newData.encapsulationType(encapsulationType);
140 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700141 }
142
143 @Override
144 public VplsData getVpls(String vplsName) {
145 requireNonNull(vplsName);
146 return vplsStore.getVpls(vplsName);
147 }
148
149 @Override
150 public Collection<Interface> removeInterfaces(VplsData vplsData, Collection<Interface> interfaces) {
151 requireNonNull(vplsData);
152 requireNonNull(interfaces);
Yi Tseng3069c612017-05-26 17:09:43 -0700153 VplsData newData = VplsData.of(vplsData);
154 newData.removeInterfaces(interfaces);
155 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700156 return interfaces;
157 }
158
159 @Override
160 public Interface removeInterface(VplsData vplsData, Interface iface) {
161 requireNonNull(vplsData);
162 requireNonNull(iface);
Yi Tseng3069c612017-05-26 17:09:43 -0700163 VplsData newData = VplsData.of(vplsData);
164 newData.removeInterface(iface);
165 updateVplsStatus(newData, VplsData.VplsState.UPDATING);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700166 return iface;
167 }
168
169 @Override
170 public void removeAllVpls() {
171 Set<VplsData> allVplses = ImmutableSet.copyOf(vplsStore.getAllVpls());
172 allVplses.forEach(this::removeVpls);
173 }
174
175 @Override
176 public Collection<VplsData> getAllVpls() {
177 return ImmutableSet.copyOf(vplsStore.getAllVpls());
178 }
179
180 /**
181 * Updates VPLS status to the store.
182 *
183 * @param vplsData the VPLS
184 * @param vplsState the new state to the VPLS
185 */
186 private void updateVplsStatus(VplsData vplsData, VplsData.VplsState vplsState) {
187 vplsData.state(vplsState);
188 vplsStore.updateVpls(vplsData);
189 }
190
191 /**
192 * A listener for host events.
193 * Updates a VPLS if host added or removed.
194 */
195 class VplsHostListener implements HostListener {
196 @Override
197 public void event(HostEvent event) {
198 Host host = event.subject();
199 Interface iface = getHostInterface(host);
200 if (iface == null) {
201 return;
202 }
203 VplsData vplsData = vplsStore.getAllVpls().stream()
204 .filter(v -> v.interfaces().contains(iface))
205 .findFirst()
206 .orElse(null);
207 if (vplsData == null) {
208 // the host does not related to any vpls
209 return;
210 }
211 updateVplsStatus(vplsData, VplsData.VplsState.UPDATING);
212 }
213
214 /**
215 * Gets the network interface of the host.
216 *
217 * @param host the host
218 * @return the network interface of the host; null if no network
219 * interface found
220 */
221 private Interface getHostInterface(Host host) {
222 Set<Interface> interfaces = interfaceService.getInterfaces();
223 return interfaces.stream()
224 .filter(iface -> iface.connectPoint().equals(host.location()) &&
225 iface.vlan().equals(host.vlan()))
226 .findFirst()
227 .orElse(null);
228 }
229 }
230
231 /**
232 * Store delegate for VPLS store.
233 * Handles VPLS store event and generate VPLS operation according to event
234 * type.
235 */
236 class VplsStoreDelegate implements StoreDelegate<VplsStoreEvent> {
237
238 @Override
239 public void notify(VplsStoreEvent event) {
240 VplsOperation vplsOperation;
241 VplsOperation.Operation op;
242 VplsData vplsData = event.subject();
243 switch (event.type()) {
244 case ADD:
245 op = VplsOperation.Operation.ADD;
246 break;
247 case REMOVE:
248 op = VplsOperation.Operation.REMOVE;
249 break;
250 case UPDATE:
251 if (vplsData.state() == VplsData.VplsState.FAILED ||
252 vplsData.state() == VplsData.VplsState.ADDED ||
253 vplsData.state() == VplsData.VplsState.REMOVED) {
254 // Update the state only. Nothing to do if it is updated
255 // to ADDED, REMOVED or FAILED
256 op = null;
257 } else {
258 op = VplsOperation.Operation.UPDATE;
259 }
260 break;
261 default:
262 log.warn(UNSUPPORTED_STORE_EVENT_TYPE, event.type());
263 return;
264 }
265 if (op != null) {
266 vplsOperation = VplsOperation.of(vplsData, op);
267 operationService.submit(vplsOperation);
268 }
269 }
270 }
271}