blob: 4a7cbcaff525125fe8149bcc515207bf3a0e85df [file] [log] [blame]
cheng fan48e832c2015-05-29 01:54:47 +08001/*
2 * Copyright 2015 Open Networking Laboratory
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 */
16package org.onosproject.provider.pcep.tunnel.impl;
17
18import static com.google.common.base.Preconditions.checkNotNull;
19import static org.onosproject.net.DeviceId.deviceId;
20import static org.onosproject.net.PortNumber.portNumber;
21import static org.slf4j.LoggerFactory.getLogger;
22
23import java.util.ArrayList;
24import java.util.HashMap;
25import java.util.List;
26import java.util.Optional;
27
28import org.apache.felix.scr.annotations.Activate;
29import org.apache.felix.scr.annotations.Component;
30import org.apache.felix.scr.annotations.Deactivate;
31import org.apache.felix.scr.annotations.Reference;
32import org.apache.felix.scr.annotations.ReferenceCardinality;
33import org.apache.felix.scr.annotations.Service;
34import org.onosproject.core.DefaultGroupId;
35import org.onosproject.incubator.net.tunnel.DefaultOpticalTunnelEndPoint;
36import org.onosproject.incubator.net.tunnel.DefaultTunnelDescription;
37import org.onosproject.incubator.net.tunnel.OpticalLogicId;
38import org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint;
39import org.onosproject.incubator.net.tunnel.Tunnel;
40import org.onosproject.incubator.net.tunnel.TunnelDescription;
41import org.onosproject.incubator.net.tunnel.TunnelEndPoint;
42import org.onosproject.incubator.net.tunnel.TunnelId;
43import org.onosproject.incubator.net.tunnel.TunnelName;
44import org.onosproject.incubator.net.tunnel.TunnelProvider;
45import org.onosproject.incubator.net.tunnel.TunnelProviderRegistry;
46import org.onosproject.incubator.net.tunnel.TunnelProviderService;
47import org.onosproject.net.ConnectPoint;
48import org.onosproject.net.DefaultAnnotations;
49import org.onosproject.net.DefaultLink;
50import org.onosproject.net.DefaultPath;
51import org.onosproject.net.DeviceId;
52import org.onosproject.net.ElementId;
53import org.onosproject.net.Link;
54import org.onosproject.net.Path;
55import org.onosproject.net.PortNumber;
56import org.onosproject.net.provider.AbstractProvider;
57import org.onosproject.net.provider.ProviderId;
58import org.onosproject.pcep.api.PcepController;
59import org.onosproject.pcep.api.PcepDpid;
60import org.onosproject.pcep.api.PcepHopNodeDescription;
61import org.onosproject.pcep.api.PcepOperator.OperationType;
62import org.onosproject.pcep.api.PcepTunnel;
cheng fan93258c72015-06-02 23:42:32 +080063import org.onosproject.pcep.api.PcepTunnel.PathState;
cheng fan48e832c2015-05-29 01:54:47 +080064import org.onosproject.pcep.api.PcepTunnel.PATHTYPE;
65import org.onosproject.pcep.api.PcepTunnelListener;
66import org.slf4j.Logger;
67
68import static org.onosproject.pcep.api.PcepDpid.*;
69
70/**
71 * Provider which uses an PCEP controller to detect, update, create network
72 * tunnels.
73 */
74@Component(immediate = true)
75@Service
76public class PcepTunnelProvider extends AbstractProvider
77 implements TunnelProvider {
78
79 private static final Logger log = getLogger(PcepTunnelProvider.class);
80 private static final long MAX_BANDWIDTH = 99999744;
81 private static final long MIN_BANDWIDTH = 64;
cheng fan7716ec92015-05-31 01:53:19 +080082 private static final String BANDWIDTH_UINT = "kbps";
cheng fan48e832c2015-05-29 01:54:47 +080083 static final String PROVIDER_ID = "org.onosproject.provider.tunnel.default";
84
85 private static final String TUNNLE_NOT_NULL = "Create failed,The given port may be wrong or has been occupied.";
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected TunnelProviderRegistry tunnelProviderRegistry;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected PcepController controller;
92
93 TunnelProviderService service;
94
95 HashMap<String, TunnelId> tunnelMap = new HashMap<String, TunnelId>();
96
97 private InnerTunnerProvider listener = new InnerTunnerProvider();
98
99 /**
100 * Creates a Tunnel provider.
101 */
102 public PcepTunnelProvider() {
103 super(new ProviderId("default", PROVIDER_ID));
104 }
105
106 @Activate
107 public void activate() {
108 service = tunnelProviderRegistry.register(this);
109 controller.addTunnelListener(listener);
110 log.info("Started");
111 }
112
113 @Deactivate
114 public void deactivate() {
115 tunnelProviderRegistry.unregister(this);
116 controller.removeTunnelListener(listener);
117 log.info("Stopped");
118 }
119
120 @Override
121 public void setupTunnel(Tunnel tunnel, Path path) {
122 // TODO Auto-generated method stub
123
124 }
125
126 @Override
127 public void setupTunnel(ElementId srcElement, Tunnel tunnel, Path path) {
128 // TODO Auto-generated method stub
129
130 }
131
132 @Override
133 public void releaseTunnel(Tunnel tunnel) {
134 // TODO Auto-generated method stub
135
136 }
137
138 @Override
139 public void releaseTunnel(ElementId srcElement, Tunnel tunnel) {
140 // TODO Auto-generated method stub
141
142 }
143
144 @Override
145 public void updateTunnel(Tunnel tunnel, Path path) {
146 // TODO Auto-generated method stub
147
148 }
149
150 @Override
151 public void updateTunnel(ElementId srcElement, Tunnel tunnel, Path path) {
152 // TODO Auto-generated method stub
153
154 }
155
156 @Override
157 public TunnelId tunnelAdded(TunnelDescription tunnel) {
158
cheng fan7716ec92015-05-31 01:53:19 +0800159 long bandwidth = Long
160 .parseLong(tunnel.annotations().value("bandwidth"));
cheng fan48e832c2015-05-29 01:54:47 +0800161
162 if (bandwidth < MIN_BANDWIDTH || bandwidth > MAX_BANDWIDTH) {
cheng fan7716ec92015-05-31 01:53:19 +0800163 error("Update failed, invalid bandwidth.");
cheng fan48e832c2015-05-29 01:54:47 +0800164 return null;
165 }
166
167 // endpoints
168 OpticalTunnelEndPoint src = (org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint) tunnel
169 .src();
170 OpticalTunnelEndPoint dst = (OpticalTunnelEndPoint) tunnel.dst();
171 // devices
172 DeviceId srcId = (DeviceId) src.elementId().get();
173 DeviceId dstId = (DeviceId) dst.elementId().get();
174
175 // ports
176 long srcPort = src.portNumber().get().toLong();
177 long dstPort = dst.portNumber().get().toLong();
178
179 // type
180 if (tunnel.type() != Tunnel.Type.VLAN) {
cheng fan7716ec92015-05-31 01:53:19 +0800181 error("Illegal tunnel type. Only support VLAN tunnel creation.");
cheng fan48e832c2015-05-29 01:54:47 +0800182 return null;
183 }
184
185 PcepTunnel pcepTunnel = controller.applyTunnel(srcId, dstId, srcPort,
186 dstPort, bandwidth,
187 tunnel.tunnelName()
188 .value());
189
190 checkNotNull(pcepTunnel, TUNNLE_NOT_NULL);
191 TunnelDescription tunnelAdded = buildOpticalTunnel(pcepTunnel, null);
192 TunnelId tunnelId = service.tunnelAdded(tunnelAdded);
193
194 tunnelMap.put(String.valueOf(pcepTunnel.id()), tunnelId);
195 return tunnelId;
196 }
197
198 @Override
199 public void tunnelRemoved(TunnelDescription tunnel) {
200 Tunnel tunnelOld = tunnelQueryById(tunnel.id());
201 checkNotNull(tunnelOld, "The tunnel id is not exsited.");
202 if (tunnelOld.type() != Tunnel.Type.VLAN) {
cheng fan93258c72015-06-02 23:42:32 +0800203 error("Illegal tunnel type. Only support VLAN tunnel deletion.");
cheng fan48e832c2015-05-29 01:54:47 +0800204 return;
205 }
206 String pcepTunnelId = getPCEPTunnelKey(tunnel.id());
207 checkNotNull(pcepTunnelId, "The tunnel id is not exsited.");
cheng fan7716ec92015-05-31 01:53:19 +0800208 if (!controller.deleteTunnel(pcepTunnelId)) {
209 error("Delete tunnel failed, Maybe some devices have been disconnected.");
210 return;
cheng fan48e832c2015-05-29 01:54:47 +0800211 }
212 tunnelMap.remove(pcepTunnelId);
213 service.tunnelRemoved(tunnel);
cheng fan48e832c2015-05-29 01:54:47 +0800214 }
215
216 @Override
217 public void tunnelUpdated(TunnelDescription tunnel) {
218
219 Tunnel tunnelOld = tunnelQueryById(tunnel.id());
220 if (tunnelOld.type() != Tunnel.Type.VLAN) {
cheng fan93258c72015-06-02 23:42:32 +0800221 error("Illegal tunnel type. Only support VLAN tunnel update.");
cheng fan48e832c2015-05-29 01:54:47 +0800222 return;
223 }
cheng fan7716ec92015-05-31 01:53:19 +0800224 long bandwidth = Long
225 .parseLong(tunnel.annotations().value("bandwidth"));
cheng fan48e832c2015-05-29 01:54:47 +0800226 if (bandwidth < MIN_BANDWIDTH || bandwidth > MAX_BANDWIDTH) {
cheng fan7716ec92015-05-31 01:53:19 +0800227 error("Update failed, invalid bandwidth.");
cheng fan48e832c2015-05-29 01:54:47 +0800228 return;
229 }
230 String pcepTunnelId = getPCEPTunnelKey(tunnel.id());
231
232 checkNotNull(pcepTunnelId, "Invalid tunnel id");
233 if (!controller.updateTunnelBandwidth(pcepTunnelId, bandwidth)) {
234
cheng fan7716ec92015-05-31 01:53:19 +0800235 error("Update failed,maybe invalid bandwidth.");
cheng fan48e832c2015-05-29 01:54:47 +0800236 return;
237
238 }
239 service.tunnelUpdated(tunnel);
240 }
241
cheng fan7716ec92015-05-31 01:53:19 +0800242 private void error(String info) {
243 System.err.println(info);
244 }
245
cheng fan48e832c2015-05-29 01:54:47 +0800246 // Short-hand for creating a connection point.
247 private ConnectPoint connectPoint(PcepDpid id, long port) {
248 return new ConnectPoint(deviceId(uri(id)), portNumber(port));
249 }
250
251 // Short-hand for creating a link.
252 private Link link(PcepDpid src, long sp, PcepDpid dst, long dp) {
253 return new DefaultLink(id(), connectPoint(src, sp), connectPoint(dst,
254 dp),
255 Link.Type.TUNNEL);
256 }
257
258 // Creates a path that leads through the given devices.
259 private Path createPath(List<PcepHopNodeDescription> hopList,
cheng fan93258c72015-06-02 23:42:32 +0800260 PATHTYPE pathtype, PathState pathState) {
cheng fan48e832c2015-05-29 01:54:47 +0800261 if (hopList == null || hopList.size() == 0) {
262 return null;
263 }
264 List<Link> links = new ArrayList<>();
265 for (int i = 1; i < hopList.size() - 1; i = i + 2) {
266 links.add(link(hopList.get(i).getDeviceId(), hopList.get(i)
267 .getPortNum(), hopList.get(i + 1).getDeviceId(), hopList
268 .get(i + 1).getPortNum()));
269 }
270
271 int hopNum = hopList.size() - 2;
272 DefaultAnnotations extendAnnotations = DefaultAnnotations.builder()
273 .set("pathNum", String.valueOf(hopNum))
cheng fan93258c72015-06-02 23:42:32 +0800274 .set("pathState", String.valueOf(pathState))
cheng fan48e832c2015-05-29 01:54:47 +0800275 .set("pathType", String.valueOf(pathtype)).build();
276 return new DefaultPath(id(), links, hopNum, extendAnnotations);
277 }
278
279 // convert the path description to a string.
280 public String pathToString(List<Link> links) {
281 StringBuilder builder = new StringBuilder();
282 builder.append("{");
283 for (Link link : links) {
284 builder.append("(Device:" + link.src().deviceId() + " Port:"
285 + link.src().port().toLong());
286 builder.append(" Device:" + link.dst().deviceId() + " Port:"
287 + link.dst().port().toLong());
288 builder.append(")");
289 }
290 builder.append("}");
291 return builder.toString();
292 }
293
294 // build a TunnelDescription.
295 private TunnelDescription buildOpticalTunnel(PcepTunnel pcepTunnel,
296 TunnelId tunnelId) {
297 TunnelEndPoint srcPoint = null;
298 TunnelEndPoint dstPoint = null;
299 Tunnel.Type tunnelType = null;
300 TunnelName name = TunnelName.tunnelName(pcepTunnel.name());
301
302 // add path after codes of tunnel's path merged
303 Path path = createPath(pcepTunnel.getHopList(),
cheng fan93258c72015-06-02 23:42:32 +0800304 pcepTunnel.getPathType(),
305 pcepTunnel.getPathState());
cheng fan48e832c2015-05-29 01:54:47 +0800306
307 OpticalTunnelEndPoint.Type endPointType = null;
308 switch (pcepTunnel.type()) {
309 case OCH:
310 tunnelType = Tunnel.Type.OCH;
311 endPointType = OpticalTunnelEndPoint.Type.LAMBDA;
312 break;
313
314 case OTN:
315 tunnelType = Tunnel.Type.ODUK;
316 endPointType = OpticalTunnelEndPoint.Type.TIMESLOT;
317 break;
318
319 case UNI:
320 tunnelType = Tunnel.Type.VLAN;
321 endPointType = null;
322 break;
323
324 default:
325 break;
326 }
327 DeviceId srcDid = deviceId(uri(pcepTunnel.srcDeviceID()));
328 DeviceId dstDid = deviceId(uri(pcepTunnel.dstDeviceId()));
329 PortNumber srcPort = PortNumber.portNumber(pcepTunnel.srcPort());
330 PortNumber dstPort = PortNumber.portNumber(pcepTunnel.dstPort());
331
332 srcPoint = new DefaultOpticalTunnelEndPoint(id(), Optional.of(srcDid),
333 Optional.of(srcPort), null,
334 endPointType,
335 OpticalLogicId.logicId(0),
336 true);
337 dstPoint = new DefaultOpticalTunnelEndPoint(id(), Optional.of(dstDid),
338 Optional.of(dstPort), null,
339 endPointType,
340 OpticalLogicId.logicId(0),
341 true);
342
343 // basic annotations
cheng fan7716ec92015-05-31 01:53:19 +0800344 DefaultAnnotations annotations = DefaultAnnotations
345 .builder()
cheng fan48e832c2015-05-29 01:54:47 +0800346 .set("SLA", String.valueOf(pcepTunnel.getSla()))
cheng fan7716ec92015-05-31 01:53:19 +0800347 .set("bandwidth",
348 String.valueOf(pcepTunnel.bandWidth()) + BANDWIDTH_UINT)
cheng fan48e832c2015-05-29 01:54:47 +0800349 .set("index", String.valueOf(pcepTunnel.id())).build();
350
cheng fan48e832c2015-05-29 01:54:47 +0800351 // a VLAN tunnel always carry OCH tunnel, this annotation is the index
352 // of a OCH tunnel.
cheng fan93258c72015-06-02 23:42:32 +0800353 if (pcepTunnel.underlayTunnelId() != 0) {
cheng fan48e832c2015-05-29 01:54:47 +0800354 DefaultAnnotations extendAnnotations = DefaultAnnotations
355 .builder()
356 .set("underLayTunnelIndex",
cheng fan93258c72015-06-02 23:42:32 +0800357 String.valueOf(pcepTunnel.underlayTunnelId())).build();
cheng fan48e832c2015-05-29 01:54:47 +0800358 annotations = DefaultAnnotations.merge(annotations,
359 extendAnnotations);
360
361 }
362 TunnelDescription tunnel = new DefaultTunnelDescription(
363 tunnelId,
364 srcPoint,
365 dstPoint,
366 tunnelType,
367 new DefaultGroupId(
368 0),
369 id(), name,
370 path,
371 annotations);
372 return tunnel;
373
374 }
375
376 /**
377 * Get the tunnelID according to the tunnel key.
378 *
379 * @param tunnelKey tunnel key
380 * @return corresponding tunnel id of the a tunnel key.
381 */
382 private TunnelId getTunnelId(String tunnelKey) {
383
384 for (String key : tunnelMap.keySet()) {
385 if (key.equals(tunnelKey)) {
386 return tunnelMap.get(key);
387 }
388 }
389 return null;
390 }
391
392 /**
393 * Get the tunnel key according to the tunnelID.
394 *
395 * @param tunnelId tunnel id
396 * @return corresponding a tunnel key of the tunnel id.
397 */
398 private String getPCEPTunnelKey(TunnelId tunnelId) {
399 for (String key : tunnelMap.keySet()) {
400 if (tunnelMap.get(key).id() == tunnelId.id()) {
401 return key;
402 }
403 }
404 return null;
405
406 }
407
408 private class InnerTunnerProvider implements PcepTunnelListener {
409
410 @Override
411 public void handlePCEPTunnel(PcepTunnel pcepTunnel) {
412
413 TunnelDescription tunnel = null;
414 // instance and id identify a tunnel together
415 String tunnelKey = String.valueOf(pcepTunnel.getInstance())
416 + String.valueOf(pcepTunnel.id());
417
418 if (tunnelKey == null || "".equals(tunnelKey)) {
419 log.error("Invalid PCEP tunnel");
420 return;
421 }
422
423 TunnelId tunnelId = getTunnelId(tunnelKey);
424
425 tunnel = buildOpticalTunnel(pcepTunnel, tunnelId);
426
427 OperationType operType = pcepTunnel.getOperationType();
428 switch (operType) {
429 case ADD:
430 tunnelId = service.tunnelAdded(tunnel);
431 tunnelMap.put(tunnelKey, tunnelId);
432 break;
433
434 case UPDATE:
435 service.tunnelUpdated(tunnel);
436 break;
437
438 case DELETE:
439 service.tunnelRemoved(tunnel);
440 tunnelMap.remove(tunnelKey);
441 break;
442
443 default:
444 log.error("Invalid tunnel operation");
445
446 }
447
448 }
449 }
450
451 @Override
452 public Tunnel tunnelQueryById(TunnelId tunnelId) {
453 return service.tunnelQueryById(tunnelId);
454 }
455
456}