blob: 27f9fd7ae1f1bf2f4b79eee3866f0075180769f2 [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.baseport.impl;
18
19import com.fasterxml.jackson.databind.JsonNode;
20import com.google.common.collect.Sets;
Mohammad Shahid4c30ea32017-08-09 18:02:10 +053021import org.onlab.packet.IpAddress;
22import org.onlab.packet.MacAddress;
23import org.onlab.util.KryoNamespace;
24import org.onosproject.core.ApplicationId;
25import org.onosproject.core.CoreService;
26import org.onosproject.evpnopenflow.rsc.BasePort;
27import org.onosproject.evpnopenflow.rsc.BasePortId;
28import org.onosproject.evpnopenflow.rsc.DefaultBasePort;
29import org.onosproject.evpnopenflow.rsc.baseport.BasePortEvent;
30import org.onosproject.evpnopenflow.rsc.baseport.BasePortListener;
31import org.onosproject.evpnopenflow.rsc.baseport.BasePortService;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.Host;
34import org.onosproject.store.serializers.KryoNamespaces;
35import org.onosproject.store.service.EventuallyConsistentMap;
36import org.onosproject.store.service.MultiValuedTimestamp;
37import org.onosproject.store.service.StorageService;
38import org.onosproject.store.service.WallClockTimestamp;
39import org.onosproject.vtnrsc.AllowedAddressPair;
40import org.onosproject.vtnrsc.BindingHostId;
41import org.onosproject.vtnrsc.DefaultFloatingIp;
42import org.onosproject.vtnrsc.FixedIp;
43import org.onosproject.vtnrsc.FloatingIp;
44import org.onosproject.vtnrsc.FloatingIpId;
45import org.onosproject.vtnrsc.RouterId;
46import org.onosproject.vtnrsc.SecurityGroup;
47import org.onosproject.vtnrsc.SubnetId;
48import org.onosproject.vtnrsc.TenantId;
49import org.onosproject.vtnrsc.TenantNetwork;
50import org.onosproject.vtnrsc.TenantNetworkId;
51import org.onosproject.vtnrsc.TenantRouter;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070052import org.osgi.service.component.annotations.Activate;
53import org.osgi.service.component.annotations.Component;
54import org.osgi.service.component.annotations.Deactivate;
55import org.osgi.service.component.annotations.Reference;
56import org.osgi.service.component.annotations.ReferenceCardinality;
Mohammad Shahid4c30ea32017-08-09 18:02:10 +053057import org.slf4j.Logger;
58import org.slf4j.LoggerFactory;
59
60import java.util.ArrayList;
61import java.util.Collection;
62import java.util.Collections;
63import java.util.HashMap;
64import java.util.List;
65import java.util.Map;
66import java.util.Set;
67import java.util.UUID;
68import java.util.stream.Collectors;
69
70import static com.google.common.base.Preconditions.checkNotNull;
71import static org.onosproject.evpnopenflow.rsc.EvpnConstants.APP_ID;
72import static org.onosproject.evpnopenflow.rsc.EvpnConstants.BASE_PORT_STORE;
73import static org.onosproject.evpnopenflow.rsc.EvpnConstants.LISTENER_NOT_NULL;
74import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RESPONSE_NOT_NULL;
75
76/**
77 * Provides implementation of the BasePort APIs.
78 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070079@Component(immediate = true, service = BasePortService.class)
Mohammad Shahid4c30ea32017-08-09 18:02:10 +053080public class BasePortManager implements BasePortService {
81
82 private final Set<BasePortListener> listeners = Sets
83 .newCopyOnWriteArraySet();
84 private final Logger log = LoggerFactory.getLogger(getClass());
85 private static final String BASEPORT_ID_NULL = "BasePort ID cannot be " +
86 "null";
87 private static final String BASEPORT_NOT_NULL = "BasePort cannot be " +
88 "null";
89 private static final String TENANTID_NOT_NULL = "TenantId cannot be null";
90 private static final String NETWORKID_NOT_NULL = "NetworkId cannot be null";
91 private static final String DEVICEID_NOT_NULL = "DeviceId cannot be null";
92 private static final String FIXEDIP_NOT_NULL = "FixedIp cannot be null";
93 private static final String MAC_NOT_NULL = "Mac address cannot be null";
94 private static final String IP_NOT_NULL = "Ip cannot be null";
95 private static final String EVENT_NOT_NULL = "event cannot be null";
96 private static final String SET = "set";
97 private static final String UPDATE = "update";
98 private static final String DELETE = "delete";
99 private static final String SLASH = "/";
100 private static final String PROTON_BASE_PORT = "Port";
101 private static final String JSON_NOT_NULL = "JsonNode can not be null";
102
103 protected EventuallyConsistentMap<BasePortId, BasePort> vPortStore;
104 protected ApplicationId appId;
105
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700106 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Mohammad Shahid4c30ea32017-08-09 18:02:10 +0530107 protected StorageService storageService;
108
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700109 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Mohammad Shahid4c30ea32017-08-09 18:02:10 +0530110 protected CoreService coreService;
111
112 @Activate
113 public void activate() {
114
115 appId = coreService.registerApplication(APP_ID);
116
117 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
118 .register(KryoNamespaces.API)
119 .register(MultiValuedTimestamp.class)
120 .register(TenantNetworkId.class)
121 .register(Host.class)
122 .register(TenantNetwork.class)
123 .register(TenantNetworkId.class)
124 .register(TenantId.class)
125 .register(SubnetId.class)
126 .register(BasePortId.class)
127 .register(BasePort.State.class)
128 .register(AllowedAddressPair.class)
129 .register(FixedIp.class)
130 .register(FloatingIp.class)
131 .register(FloatingIpId.class)
132 .register(FloatingIp.Status.class)
133 .register(UUID.class)
134 .register(DefaultFloatingIp.class)
135 .register(BindingHostId.class)
136 .register(SecurityGroup.class)
137 .register(IpAddress.class)
138 .register(DefaultBasePort.class)
139 .register(RouterId.class)
140 .register(TenantRouter.class)
141 .register(BasePort.class);
142 vPortStore = storageService
143 .<BasePortId, BasePort>eventuallyConsistentMapBuilder()
144 .withName(BASE_PORT_STORE).withSerializer(serializer)
145 .withTimestampProvider((k, v) -> new WallClockTimestamp())
146 .build();
147 log.info("Started");
148 }
149
150 @Deactivate
151 public void deactivate() {
152 vPortStore.destroy();
153 log.info("Stoppped");
154 }
155
156 @Override
157 public boolean exists(BasePortId vPortId) {
158 checkNotNull(vPortId, BASEPORT_ID_NULL);
159 return vPortStore.containsKey(vPortId);
160 }
161
162 @Override
163 public BasePort getPort(BasePortId vPortId) {
164 checkNotNull(vPortId, BASEPORT_ID_NULL);
165 return vPortStore.get(vPortId);
166 }
167
168 @Override
169 public BasePort getPort(FixedIp fixedIP) {
170 checkNotNull(fixedIP, FIXEDIP_NOT_NULL);
171 List<BasePort> vPorts = new ArrayList<>();
172 vPortStore.values().forEach(p -> {
173 for (FixedIp fixedIp : p.fixedIps()) {
174 if (fixedIp.equals(fixedIP)) {
175 vPorts.add(p);
176 break;
177 }
178 }
179 });
180 if (vPorts.size() == 0) {
181 return null;
182 }
183 return vPorts.get(0);
184 }
185
186 @Override
187 public BasePort getPort(MacAddress mac) {
188 checkNotNull(mac, MAC_NOT_NULL);
189 List<BasePort> vPorts = new ArrayList<>();
190 vPortStore.values().forEach(p -> {
191 if (p.macAddress().equals(mac)) {
192 vPorts.add(p);
193 }
194 });
195 if (vPorts.size() == 0) {
196 return null;
197 }
198 return vPorts.get(0);
199 }
200
201 @Override
202 public BasePort getPort(TenantNetworkId networkId, IpAddress ip) {
203 checkNotNull(networkId, NETWORKID_NOT_NULL);
204 checkNotNull(ip, IP_NOT_NULL);
205 List<BasePort> vPorts = new ArrayList<>();
206 vPortStore.values().stream().filter(p -> p.networkId().equals(networkId))
207 .forEach(p -> {
208 for (FixedIp fixedIp : p.fixedIps()) {
209 if (fixedIp.ip().equals(ip)) {
210 vPorts.add(p);
211 break;
212 }
213 }
214 });
215 if (vPorts.size() == 0) {
216 return null;
217 }
218 return vPorts.get(0);
219 }
220
221 @Override
222 public Collection<BasePort> getPorts() {
223 return Collections.unmodifiableCollection(vPortStore.values());
224 }
225
226 @Override
227 public Collection<BasePort> getPorts(TenantNetworkId networkId) {
228 checkNotNull(networkId, NETWORKID_NOT_NULL);
229 return vPortStore.values().stream().filter(d -> d.networkId().equals(networkId))
230 .collect(Collectors.toList());
231 }
232
233 @Override
234 public Collection<BasePort> getPorts(TenantId tenantId) {
235 checkNotNull(tenantId, TENANTID_NOT_NULL);
236 return vPortStore.values().stream().filter(d -> d.tenantId().equals(tenantId))
237 .collect(Collectors.toList());
238 }
239
240 @Override
241 public Collection<BasePort> getPorts(DeviceId deviceId) {
242 checkNotNull(deviceId, DEVICEID_NOT_NULL);
243 return vPortStore.values().stream().filter(d -> d.deviceId().equals(deviceId))
244 .collect(Collectors.toList());
245 }
246
247 @Override
248 public boolean createPorts(Iterable<BasePort> vPorts) {
249 checkNotNull(vPorts, BASEPORT_NOT_NULL);
250 for (BasePort vPort : vPorts) {
251 log.info("vPortId is {} ", vPort.portId().toString());
252 vPortStore.put(vPort.portId(), vPort);
253 if (!vPortStore.containsKey(vPort.portId())) {
254 log.info("The basePort is created failed whose identifier is" +
255 " {} ",
256 vPort.portId().toString());
257 return false;
258 }
259 }
260 return true;
261 }
262
263 @Override
264 public boolean updatePorts(Iterable<BasePort> vPorts) {
265 checkNotNull(vPorts, BASEPORT_NOT_NULL);
266 for (BasePort vPort : vPorts) {
267 vPortStore.put(vPort.portId(), vPort);
268 if (!vPortStore.containsKey(vPort.portId())) {
269 log.info("The basePort is not exist whose identifier is {}",
270 vPort.portId().toString());
271 return false;
272 }
273
274 vPortStore.put(vPort.portId(), vPort);
275
276 if (!vPort.equals(vPortStore.get(vPort.portId()))) {
277 log.info("The basePort is updated failed whose identifier " +
278 "is {}",
279 vPort.portId().toString());
280 return false;
281 }
282 }
283 return true;
284 }
285
286 @Override
287 public boolean removePorts(Iterable<BasePortId> vPortIds) {
288 checkNotNull(vPortIds, BASEPORT_ID_NULL);
289 for (BasePortId vPortId : vPortIds) {
290 vPortStore.remove(vPortId);
291 if (vPortStore.containsKey(vPortId)) {
292 log.info("The basePort is removed failed whose identifier is" +
293 " {}",
294 vPortId.toString());
295 return false;
296 }
297 }
298 return true;
299 }
300
301 /**
302 * Returns a collection of basePorts from subnetNodes.
303 *
304 * @param vPortNodes the basePort json node
305 * @return BasePort collection of vpn ports
306 */
307 private Collection<BasePort> changeJsonToSub(JsonNode vPortNodes) {
308 checkNotNull(vPortNodes, JSON_NOT_NULL);
309 Set<FixedIp> fixedIps = null;
310 TenantNetworkId tenantNetworkId = null;
311 Map<BasePortId, BasePort> vportMap = new HashMap<>();
312 Map<String, String> strMap = new HashMap<>();
313 BasePortId basePortId = BasePortId.portId(vPortNodes.get("id").asText());
314 String name = vPortNodes.get("name").asText();
315 TenantId tenantId = TenantId
316 .tenantId(vPortNodes.get("tenant_id").asText());
317 Boolean adminStateUp = vPortNodes.get("admin_state_up").asBoolean();
318 String state = vPortNodes.get("status").asText();
319 MacAddress macAddress = MacAddress
320 .valueOf(vPortNodes.get("mac_address").asText());
321 DeviceId deviceId = DeviceId
322 .deviceId(vPortNodes.get("device_id").asText());
323 String deviceOwner = vPortNodes.get("device_owner").asText();
324 BindingHostId bindingHostId = BindingHostId
325 .bindingHostId(vPortNodes.get("host_id").asText());
326 String bindingVnicType = vPortNodes.get("vnic_type").asText();
327 String bindingVifType = vPortNodes.get("vif_type").asText();
328 String bindingVifDetails = vPortNodes.get("vif_details").asText();
329 strMap.put("name", name);
330 strMap.put("deviceOwner", deviceOwner);
331 strMap.put("bindingVnicType", bindingVnicType);
332 strMap.put("bindingVifType", bindingVifType);
333 strMap.put("bindingVifDetails", bindingVifDetails);
334 BasePort prevBasePort = getPort(basePortId);
335 if (prevBasePort != null) {
336 fixedIps = prevBasePort.fixedIps();
337 tenantNetworkId = prevBasePort.networkId();
338 }
339 BasePort vPort = new DefaultBasePort(basePortId,
340 tenantNetworkId,
341 adminStateUp,
342 strMap, state,
343 macAddress, tenantId,
344 deviceId, fixedIps,
345 bindingHostId,
346 null,
347 null);
348 vportMap.put(basePortId, vPort);
349
350 return Collections.unmodifiableCollection(vportMap.values());
351 }
352
353 /**
354 * Returns BasePort State.
355 *
356 * @param state the base port state
357 * @return the basePort state
358 */
359 private BasePort.State isState(String state) {
360 if (state.equals("ACTIVE")) {
361 return BasePort.State.ACTIVE;
362 } else {
363 return BasePort.State.DOWN;
364 }
365
366 }
367
368 /**
369 * process Etcd response for port information.
370 *
371 * @param action can be either update or delete
372 * @param key can contain the id and also target information
373 * @param value content of the port configuration
374 */
375 @Override
376 public void processGluonConfig(String action, String key, JsonNode value) {
377 Collection<BasePort> basePorts;
378 switch (action) {
379 case DELETE:
380 String[] list = key.split(SLASH);
381 BasePortId basePortId
382 = BasePortId.portId(list[list.length - 1]);
383 Set<BasePortId> basePortIds = Sets.newHashSet(basePortId);
384 removePorts(basePortIds);
385 break;
386 case SET:
387 checkNotNull(value, RESPONSE_NOT_NULL);
388 basePorts = changeJsonToSub(value);
389 createPorts(basePorts);
390 break;
391 case UPDATE:
392 checkNotNull(value, RESPONSE_NOT_NULL);
393 basePorts = changeJsonToSub(value);
394 updatePorts(basePorts);
395 break;
396 default:
397 log.info("Invalid action is received while processing VPN " +
398 "port configuration");
399 }
400 }
401
402 private void parseEtcdResponse(JsonNode jsonNode,
403 String key,
404 String action) {
405 JsonNode modifyValue = null;
406 if (action.equals(SET)) {
407 modifyValue = jsonNode.get(key);
408 }
409 String[] list = key.split(SLASH);
410 String target = list[list.length - 2];
411 if (target.equals(PROTON_BASE_PORT)) {
412 processGluonConfig(action, key, modifyValue);
413 }
414 }
415
416 @Override
417 public void addListener(BasePortListener listener) {
418 checkNotNull(listener, LISTENER_NOT_NULL);
419 listeners.add(listener);
420 }
421
422 @Override
423 public void removeListener(BasePortListener listener) {
424 checkNotNull(listener, LISTENER_NOT_NULL);
425 listeners.remove(listener);
426 }
427
428 /**
429 * Notifies specify event to all listeners.
430 *
431 * @param event vpn af config event
432 */
433 private void notifyListeners(BasePortEvent event) {
434 checkNotNull(event, EVENT_NOT_NULL);
435 listeners.forEach(listener -> listener.event(event));
436 }
437}