blob: 2babba61cbf0b6530b7adaa3a0b6add0c7fd0e9b [file] [log] [blame]
Mohammad Shahid4c30ea32017-08-09 18:02:10 +05301/*
2 * Copyright 2017-present Open Networking Foundation
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 */
16
17package org.onosproject.evpnopenflow.rsc.vpnport.impl;
18
19import com.fasterxml.jackson.databind.JsonNode;
20import com.google.common.collect.Sets;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
27import org.onlab.packet.IpAddress;
28import org.onlab.packet.IpPrefix;
29import org.onlab.packet.MacAddress;
30import org.onlab.util.KryoNamespace;
31import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
33import org.onosproject.evpnopenflow.rsc.BasePort;
34import org.onosproject.evpnopenflow.rsc.BasePortId;
35import org.onosproject.evpnopenflow.rsc.DefaultVpnPort;
36import org.onosproject.evpnopenflow.rsc.VpnInstanceId;
37import org.onosproject.evpnopenflow.rsc.VpnPort;
38import org.onosproject.evpnopenflow.rsc.VpnPortId;
39import org.onosproject.evpnopenflow.rsc.baseport.BasePortService;
40import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortEvent;
41import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortListener;
42import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortService;
43import org.onosproject.net.DeviceId;
44import org.onosproject.store.serializers.KryoNamespaces;
45import org.onosproject.store.service.EventuallyConsistentMap;
46import org.onosproject.store.service.StorageService;
47import org.onosproject.store.service.WallClockTimestamp;
48import org.onosproject.vtnrsc.AllocationPool;
49import org.onosproject.vtnrsc.BindingHostId;
50import org.onosproject.vtnrsc.DefaultSubnet;
51import org.onosproject.vtnrsc.DefaultTenantNetwork;
52import org.onosproject.vtnrsc.DefaultVirtualPort;
53import org.onosproject.vtnrsc.FixedIp;
54import org.onosproject.vtnrsc.HostRoute;
55import org.onosproject.vtnrsc.PhysicalNetwork;
56import org.onosproject.vtnrsc.SegmentationId;
57import org.onosproject.vtnrsc.Subnet;
58import org.onosproject.vtnrsc.SubnetId;
59import org.onosproject.vtnrsc.TenantId;
60import org.onosproject.vtnrsc.TenantNetwork;
61import org.onosproject.vtnrsc.TenantNetworkId;
62import org.onosproject.vtnrsc.VirtualPort;
63import org.onosproject.vtnrsc.VirtualPortId;
64import org.onosproject.vtnrsc.subnet.SubnetService;
65import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
66import org.onosproject.vtnrsc.virtualport.VirtualPortService;
67import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
69
70import java.util.Collection;
71import java.util.Collections;
72import java.util.HashMap;
73import java.util.HashSet;
74import java.util.Map;
75import java.util.Set;
76
77import static com.google.common.base.Preconditions.checkNotNull;
78import static org.onosproject.evpnopenflow.rsc.EvpnConstants.APP_ID;
79import static org.onosproject.evpnopenflow.rsc.EvpnConstants.DELETE;
80import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVENT_NOT_NULL;
81import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_PORT_START;
82import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_PORT_STOP;
83import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INTERFACE_ID;
84import static org.onosproject.evpnopenflow.rsc.EvpnConstants.JSON_NOT_NULL;
85import static org.onosproject.evpnopenflow.rsc.EvpnConstants.LISTENER_NOT_NULL;
86import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RESPONSE_NOT_NULL;
87import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SET;
88import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SLASH;
89import static org.onosproject.evpnopenflow.rsc.EvpnConstants.UPDATE;
90import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE;
91import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_CREATION_FAILED;
92import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_DELETE_FAILED;
93import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_ID;
94import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_ID_NOT_NULL;
95import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_IS_NOT_EXIST;
96import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_NOT_NULL;
97import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_STORE;
98import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_UPDATE_FAILED;
99
100/**
101 * Provides implementation of the VpnPort service.
102 */
103@Component(immediate = true)
104@Service
105public class VpnPortManager implements VpnPortService {
106
107 private final Logger log = LoggerFactory.getLogger(getClass());
108 private final Set<VpnPortListener> listeners = Sets
109 .newCopyOnWriteArraySet();
110
111 protected EventuallyConsistentMap<VpnPortId, VpnPort> vpnPortStore;
112 protected ApplicationId appId;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected StorageService storageService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected CoreService coreService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected BasePortService basePortService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected VirtualPortService virtualPortService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected TenantNetworkService tenantNetworkService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected SubnetService subnetService;
131
132 @Activate
133
134 public void activate() {
135 appId = coreService.registerApplication(APP_ID);
136 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
137 .register(KryoNamespaces.API).register(VpnPort.class)
138 .register(VpnPortId.class);
139 vpnPortStore = storageService
140 .<VpnPortId, VpnPort>eventuallyConsistentMapBuilder()
141 .withName(VPN_PORT_STORE).withSerializer(serializer)
142 .withTimestampProvider((k, v) -> new WallClockTimestamp())
143 .build();
144 log.info(EVPN_VPN_PORT_START);
145 }
146
147 @Deactivate
148 public void deactivate() {
149 vpnPortStore.destroy();
150 log.info(EVPN_VPN_PORT_STOP);
151 }
152
153 @Override
154 public boolean exists(VpnPortId vpnPortId) {
155 checkNotNull(vpnPortId, VPN_PORT_ID_NOT_NULL);
156 return vpnPortStore.containsKey(vpnPortId);
157 }
158
159 @Override
160 public VpnPort getPort(VpnPortId vpnPortId) {
161 checkNotNull(vpnPortId, VPN_PORT_ID_NOT_NULL);
162 return vpnPortStore.get(vpnPortId);
163 }
164
165 @Override
166 public Collection<VpnPort> getPorts() {
167 return Collections.unmodifiableCollection(vpnPortStore.values());
168 }
169
170 @Override
171 public boolean createPorts(Iterable<VpnPort> vpnPorts) {
172 checkNotNull(vpnPorts, VPN_PORT_NOT_NULL);
173 for (VpnPort vpnPort : vpnPorts) {
174 log.info(VPN_PORT_ID, vpnPort.id().toString());
175 vpnPortStore.put(vpnPort.id(), vpnPort);
176 if (!vpnPortStore.containsKey(vpnPort.id())) {
177 log.info(VPN_PORT_CREATION_FAILED, vpnPort.id().toString());
178 return false;
179 }
180 notifyListeners(new VpnPortEvent(VpnPortEvent.Type.VPN_PORT_SET,
181 vpnPort));
182 }
183 return true;
184 }
185
186 @Override
187 public boolean updatePorts(Iterable<VpnPort> vpnPorts) {
188 checkNotNull(vpnPorts, VPN_PORT_NOT_NULL);
189 for (VpnPort vpnPort : vpnPorts) {
190 if (!vpnPortStore.containsKey(vpnPort.id())) {
191 log.info(VPN_PORT_IS_NOT_EXIST, vpnPort.id().toString());
192 return false;
193 }
194 vpnPortStore.put(vpnPort.id(), vpnPort);
195 if (!vpnPort.equals(vpnPortStore.get(vpnPort.id()))) {
196 log.info(VPN_PORT_UPDATE_FAILED, vpnPort.id().toString());
197 return false;
198 }
199 notifyListeners(new VpnPortEvent(VpnPortEvent.Type.VPN_PORT_UPDATE,
200 vpnPort));
201 }
202 return true;
203 }
204
205 @Override
206 public boolean removePorts(Iterable<VpnPortId> vpnPortIds) {
207 checkNotNull(vpnPortIds, VPN_PORT_NOT_NULL);
208 for (VpnPortId vpnPortid : vpnPortIds) {
209 VpnPort vpnPort = vpnPortStore.get(vpnPortid);
210 vpnPortStore.remove(vpnPortid);
211 if (vpnPortStore.containsKey(vpnPortid)) {
212 log.info(VPN_PORT_DELETE_FAILED, vpnPortid.toString());
213 return false;
214 }
215 notifyListeners(new VpnPortEvent(VpnPortEvent.Type.VPN_PORT_DELETE,
216 vpnPort));
217 }
218 return true;
219 }
220
221 @Override
222 public void processGluonConfig(String action, String key, JsonNode value) {
223 Collection<VpnPort> vpnPorts;
224 switch (action) {
225 case DELETE:
226 String[] list = key.split(SLASH);
227 VpnPortId vpnPortId
228 = VpnPortId.vpnPortId(list[list.length - 1]);
229 Set<VpnPortId> vpnPortIds = Sets.newHashSet(vpnPortId);
230 removePorts(vpnPortIds);
231 // After removing vpn port and also remove virtual port from vtn
232 VirtualPortId virtualPortId
233 = VirtualPortId.portId(list[list.length - 1]);
234 Set<VirtualPortId> virtualPortIds
235 = Sets.newHashSet(virtualPortId);
236 virtualPortService.removePorts(virtualPortIds);
237 break;
238 case SET:
239 checkNotNull(value, RESPONSE_NOT_NULL);
240 vpnPorts = changeJsonToSub(value);
241 createPorts(vpnPorts);
242 break;
243 case UPDATE:
244 checkNotNull(value, RESPONSE_NOT_NULL);
245 vpnPorts = changeJsonToSub(value);
246 updatePorts(vpnPorts);
247 break;
248 default:
249 log.info("Invalid action is received while processing VPN " +
250 "port configuration");
251 }
252 }
253
254 /**
255 * Creates dummy gluon network to the VTN.
256 *
257 * @param state the base port state
258 * @param adminStateUp the base port admin status
259 * @param tenantID the base port tenant ID
260 */
261 private void createDummyGluonNetwork(boolean adminStateUp, String state,
262 TenantId tenantID) {
263 String id = "11111111-1111-1111-1111-111111111111";
264 String name = "GluonNetwork";
265 String segmentationID = "50";
266 String physicalNetwork = "None";
267
268 TenantNetwork network = new DefaultTenantNetwork(TenantNetworkId.networkId(id), name,
269 adminStateUp,
270 TenantNetwork.State.valueOf(state),
271 false, tenantID,
272 false,
273 TenantNetwork.Type.LOCAL,
274 PhysicalNetwork.physicalNetwork(physicalNetwork),
275 SegmentationId.segmentationId(segmentationID));
276
277 Set<TenantNetwork> networksSet = Sets.newHashSet(network);
278 tenantNetworkService.createNetworks(networksSet);
279 }
280
281
282 /**
283 * Creates dummy gluon subnet to the VTN.
284 *
285 * @param tenantId the base port tenant ID
286 */
287 public void createDummySubnet(TenantId tenantId) {
288 String id = "22222222-2222-2222-2222-222222222222";
289 String subnetName = "GluonSubnet";
290 String cidr = "0.0.0.0/0";
291 String gatewayIp = "0.0.0.0";
292 Set<HostRoute> hostRoutes = Sets.newHashSet();
Mohammad Shahid4c30ea32017-08-09 18:02:10 +0530293 TenantNetworkId tenantNetworkId = null;
294 Set<AllocationPool> allocationPools = Sets.newHashSet();
295 Iterable<TenantNetwork> networks
296 = tenantNetworkService.getNetworks();
297
298 for (TenantNetwork tenantNetwork : networks) {
299 if (tenantNetwork.name().equals("GluonNetwork")) {
300 tenantNetworkId = tenantNetwork.id();
301 break;
302 }
303 }
304 Subnet subnet = new DefaultSubnet(SubnetId.subnetId(id), subnetName,
305 tenantNetworkId,
306 tenantId, IpAddress.Version.INET,
Ray Milkeyfe0e0852018-01-18 11:14:05 -0800307 IpPrefix.valueOf(cidr),
308 IpAddress.valueOf(gatewayIp),
Mohammad Shahid4c30ea32017-08-09 18:02:10 +0530309 false, false, hostRoutes,
Ray Milkeyfe0e0852018-01-18 11:14:05 -0800310 null,
311 null,
Mohammad Shahid4c30ea32017-08-09 18:02:10 +0530312 allocationPools);
313
314 Set<Subnet> subnetsSet = Sets.newHashSet(subnet);
315 subnetService.createSubnets(subnetsSet);
316 }
317
318 /**
319 * Returns a collection of vpnPort from subnetNodes.
320 *
321 * @param vpnPortNodes the vpnPort json node
322 * @return list of vpnports
323 */
324 private Collection<VpnPort> changeJsonToSub(JsonNode vpnPortNodes) {
325 checkNotNull(vpnPortNodes, JSON_NOT_NULL);
326 Map<VpnPortId, VpnPort> vpnPortMap = new HashMap<>();
327 String interfaceId = vpnPortNodes.get(INTERFACE_ID).asText();
328 VpnPortId vpnPortId = VpnPortId.vpnPortId(interfaceId);
329 VpnInstanceId vpnInstanceId = VpnInstanceId
330 .vpnInstanceId(vpnPortNodes.get(VPN_INSTANCE).asText());
331 VpnPort vpnPort = new DefaultVpnPort(vpnPortId, vpnInstanceId);
332 vpnPortMap.put(vpnPortId, vpnPort);
333 // update ip address and tenant network information in vtn
334 TenantNetworkId tenantNetworkId = null;
335 Map<VirtualPortId, VirtualPort> vPortMap = new HashMap<>();
336 BasePortId basePortId = BasePortId.portId(interfaceId);
337 VirtualPortId virtualPortId = VirtualPortId.portId(interfaceId);
338 BasePort bPort = basePortService.getPort(basePortId);
339 if (bPort != null) {
340 FixedIp fixedIp = FixedIp.fixedIp(SubnetId.subnetId(basePortId.toString()),
341 IpAddress.valueOf(vpnPortNodes
342 .get("ipaddress").asText()));
343 Set<FixedIp> fixedIps = new HashSet<>();
344 fixedIps.add(fixedIp);
345 Map<String, String> strMap = new HashMap<>();
346 boolean adminStateUp = bPort.adminStateUp();
347 strMap.put("name", bPort.name());
348 strMap.put("deviceOwner", bPort.deviceOwner());
349 strMap.put("bindingVnicType", bPort.bindingVnicType());
350 strMap.put("bindingVifType", bPort.bindingVifType());
351 strMap.put("bindingVifDetails", bPort.bindingVifDetails());
352 String state = bPort.state();
353 MacAddress macAddress = bPort.macAddress();
354 TenantId tenantId = bPort.tenantId();
355 DeviceId deviceId = bPort.deviceId();
356 BindingHostId bindingHostId = bPort.bindingHostId();
357 // Creates Dummy Gluon Network and Subnet
358 createDummyGluonNetwork(adminStateUp, state, tenantId);
359 createDummySubnet(tenantId);
360
361 Iterable<TenantNetwork> networks
362 = tenantNetworkService.getNetworks();
363
364 for (TenantNetwork tenantNetwork : networks) {
365 if (tenantNetwork.name().equals("GluonNetwork")) {
366 tenantNetworkId = tenantNetwork.id();
367 break;
368 }
369 }
370 if (tenantNetworkId != null) {
371
372 DefaultVirtualPort vPort = new DefaultVirtualPort(virtualPortId,
373 tenantNetworkId,
374 adminStateUp,
375 strMap, isState(state),
376 macAddress, tenantId,
377 deviceId, fixedIps,
378 bindingHostId,
379 null,
380 null);
381 vPortMap.put(virtualPortId, vPort);
382 Collection<VirtualPort> virtualPorts
383 = Collections.unmodifiableCollection(vPortMap.values());
384 virtualPortService.createPorts(virtualPorts);
385 }
386 }
387
388 return Collections.unmodifiableCollection(vpnPortMap.values());
389 }
390
391 /**
392 * Returns BasePort State.
393 *
394 * @param state the base port state
395 * @return the basePort state
396 */
397 private VirtualPort.State isState(String state) {
398 if (state.equals("ACTIVE")) {
399 return VirtualPort.State.ACTIVE;
400 } else {
401 return VirtualPort.State.DOWN;
402 }
403
404 }
405
406 @Override
407 public void addListener(VpnPortListener listener) {
408 checkNotNull(listener, LISTENER_NOT_NULL);
409 listeners.add(listener);
410 }
411
412 @Override
413 public void removeListener(VpnPortListener listener) {
414 checkNotNull(listener, LISTENER_NOT_NULL);
415 listeners.remove(listener);
416 }
417
418 /**
419 * Notifies specify event to all listeners.
420 *
421 * @param event Vpn Port event
422 */
423 private void notifyListeners(VpnPortEvent event) {
424 checkNotNull(event, EVENT_NOT_NULL);
425 listeners.forEach(listener -> {
426 listener.event(event);
427 });
428 }
429}