blob: ec4d3dd456d5bd98e4ccc0dc0d94e857eb53b493 [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;
63import org.onosproject.pcep.api.PcepTunnel.PATHTYPE;
64import org.onosproject.pcep.api.PcepTunnelListener;
65import org.slf4j.Logger;
66
67import static org.onosproject.pcep.api.PcepDpid.*;
68
69/**
70 * Provider which uses an PCEP controller to detect, update, create network
71 * tunnels.
72 */
73@Component(immediate = true)
74@Service
75public class PcepTunnelProvider extends AbstractProvider
76 implements TunnelProvider {
77
78 private static final Logger log = getLogger(PcepTunnelProvider.class);
79 private static final long MAX_BANDWIDTH = 99999744;
80 private static final long MIN_BANDWIDTH = 64;
81 static final String PROVIDER_ID = "org.onosproject.provider.tunnel.default";
82
83 private static final String TUNNLE_NOT_NULL = "Create failed,The given port may be wrong or has been occupied.";
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected TunnelProviderRegistry tunnelProviderRegistry;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected PcepController controller;
90
91 TunnelProviderService service;
92
93 HashMap<String, TunnelId> tunnelMap = new HashMap<String, TunnelId>();
94
95 private InnerTunnerProvider listener = new InnerTunnerProvider();
96
97 /**
98 * Creates a Tunnel provider.
99 */
100 public PcepTunnelProvider() {
101 super(new ProviderId("default", PROVIDER_ID));
102 }
103
104 @Activate
105 public void activate() {
106 service = tunnelProviderRegistry.register(this);
107 controller.addTunnelListener(listener);
108 log.info("Started");
109 }
110
111 @Deactivate
112 public void deactivate() {
113 tunnelProviderRegistry.unregister(this);
114 controller.removeTunnelListener(listener);
115 log.info("Stopped");
116 }
117
118 @Override
119 public void setupTunnel(Tunnel tunnel, Path path) {
120 // TODO Auto-generated method stub
121
122 }
123
124 @Override
125 public void setupTunnel(ElementId srcElement, Tunnel tunnel, Path path) {
126 // TODO Auto-generated method stub
127
128 }
129
130 @Override
131 public void releaseTunnel(Tunnel tunnel) {
132 // TODO Auto-generated method stub
133
134 }
135
136 @Override
137 public void releaseTunnel(ElementId srcElement, Tunnel tunnel) {
138 // TODO Auto-generated method stub
139
140 }
141
142 @Override
143 public void updateTunnel(Tunnel tunnel, Path path) {
144 // TODO Auto-generated method stub
145
146 }
147
148 @Override
149 public void updateTunnel(ElementId srcElement, Tunnel tunnel, Path path) {
150 // TODO Auto-generated method stub
151
152 }
153
154 @Override
155 public TunnelId tunnelAdded(TunnelDescription tunnel) {
156
157 long bandwidth = Long.parseLong(tunnel.annotations().value("bandWith"));
158
159 if (bandwidth < MIN_BANDWIDTH || bandwidth > MAX_BANDWIDTH) {
160 System.out.println("Update failed, invalid bandwidth.");
161 return null;
162 }
163
164 // endpoints
165 OpticalTunnelEndPoint src = (org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint) tunnel
166 .src();
167 OpticalTunnelEndPoint dst = (OpticalTunnelEndPoint) tunnel.dst();
168 // devices
169 DeviceId srcId = (DeviceId) src.elementId().get();
170 DeviceId dstId = (DeviceId) dst.elementId().get();
171
172 // ports
173 long srcPort = src.portNumber().get().toLong();
174 long dstPort = dst.portNumber().get().toLong();
175
176 // type
177 if (tunnel.type() != Tunnel.Type.VLAN) {
178 System.out
179 .println("Llegal tunnel type. Only support VLAN tunnel creation.");
180 return null;
181 }
182
183 PcepTunnel pcepTunnel = controller.applyTunnel(srcId, dstId, srcPort,
184 dstPort, bandwidth,
185 tunnel.tunnelName()
186 .value());
187
188 checkNotNull(pcepTunnel, TUNNLE_NOT_NULL);
189 TunnelDescription tunnelAdded = buildOpticalTunnel(pcepTunnel, null);
190 TunnelId tunnelId = service.tunnelAdded(tunnelAdded);
191
192 tunnelMap.put(String.valueOf(pcepTunnel.id()), tunnelId);
193 return tunnelId;
194 }
195
196 @Override
197 public void tunnelRemoved(TunnelDescription tunnel) {
198 Tunnel tunnelOld = tunnelQueryById(tunnel.id());
199 checkNotNull(tunnelOld, "The tunnel id is not exsited.");
200 if (tunnelOld.type() != Tunnel.Type.VLAN) {
201 System.out
202 .println("Llegal tunnel type. Only support VLAN tunnel deletion.");
203 return;
204 }
205 String pcepTunnelId = getPCEPTunnelKey(tunnel.id());
206 checkNotNull(pcepTunnelId, "The tunnel id is not exsited.");
207 if (controller.deleteTunnel(pcepTunnelId)) {
208 log.info("delete tunnel:" + pcepTunnelId + "ok.");
209 }
210 tunnelMap.remove(pcepTunnelId);
211 service.tunnelRemoved(tunnel);
212
213 }
214
215 @Override
216 public void tunnelUpdated(TunnelDescription tunnel) {
217
218 Tunnel tunnelOld = tunnelQueryById(tunnel.id());
219 if (tunnelOld.type() != Tunnel.Type.VLAN) {
220 System.out
221 .println("Llegal tunnel type. Only support VLAN tunnel update.");
222 return;
223 }
224 long bandwidth = Long.parseLong(tunnel.annotations().value("bandWith"));
225 if (bandwidth < MIN_BANDWIDTH || bandwidth > MAX_BANDWIDTH) {
226 System.out.println("Update failed, invalid bandwidth.");
227 return;
228 }
229 String pcepTunnelId = getPCEPTunnelKey(tunnel.id());
230
231 checkNotNull(pcepTunnelId, "Invalid tunnel id");
232 if (!controller.updateTunnelBandwidth(pcepTunnelId, bandwidth)) {
233
234 System.out.println("Update failed,maybe invalid bandwidth.");
235 return;
236
237 }
238 service.tunnelUpdated(tunnel);
239 }
240
241 // Short-hand for creating a connection point.
242 private ConnectPoint connectPoint(PcepDpid id, long port) {
243 return new ConnectPoint(deviceId(uri(id)), portNumber(port));
244 }
245
246 // Short-hand for creating a link.
247 private Link link(PcepDpid src, long sp, PcepDpid dst, long dp) {
248 return new DefaultLink(id(), connectPoint(src, sp), connectPoint(dst,
249 dp),
250 Link.Type.TUNNEL);
251 }
252
253 // Creates a path that leads through the given devices.
254 private Path createPath(List<PcepHopNodeDescription> hopList,
255 PATHTYPE pathtype) {
256 if (hopList == null || hopList.size() == 0) {
257 return null;
258 }
259 List<Link> links = new ArrayList<>();
260 for (int i = 1; i < hopList.size() - 1; i = i + 2) {
261 links.add(link(hopList.get(i).getDeviceId(), hopList.get(i)
262 .getPortNum(), hopList.get(i + 1).getDeviceId(), hopList
263 .get(i + 1).getPortNum()));
264 }
265
266 int hopNum = hopList.size() - 2;
267 DefaultAnnotations extendAnnotations = DefaultAnnotations.builder()
268 .set("pathNum", String.valueOf(hopNum))
269 .set("pathType", String.valueOf(pathtype)).build();
270 return new DefaultPath(id(), links, hopNum, extendAnnotations);
271 }
272
273 // convert the path description to a string.
274 public String pathToString(List<Link> links) {
275 StringBuilder builder = new StringBuilder();
276 builder.append("{");
277 for (Link link : links) {
278 builder.append("(Device:" + link.src().deviceId() + " Port:"
279 + link.src().port().toLong());
280 builder.append(" Device:" + link.dst().deviceId() + " Port:"
281 + link.dst().port().toLong());
282 builder.append(")");
283 }
284 builder.append("}");
285 return builder.toString();
286 }
287
288 // build a TunnelDescription.
289 private TunnelDescription buildOpticalTunnel(PcepTunnel pcepTunnel,
290 TunnelId tunnelId) {
291 TunnelEndPoint srcPoint = null;
292 TunnelEndPoint dstPoint = null;
293 Tunnel.Type tunnelType = null;
294 TunnelName name = TunnelName.tunnelName(pcepTunnel.name());
295
296 // add path after codes of tunnel's path merged
297 Path path = createPath(pcepTunnel.getHopList(),
298 pcepTunnel.getPathType());
299
300 OpticalTunnelEndPoint.Type endPointType = null;
301 switch (pcepTunnel.type()) {
302 case OCH:
303 tunnelType = Tunnel.Type.OCH;
304 endPointType = OpticalTunnelEndPoint.Type.LAMBDA;
305 break;
306
307 case OTN:
308 tunnelType = Tunnel.Type.ODUK;
309 endPointType = OpticalTunnelEndPoint.Type.TIMESLOT;
310 break;
311
312 case UNI:
313 tunnelType = Tunnel.Type.VLAN;
314 endPointType = null;
315 break;
316
317 default:
318 break;
319 }
320 DeviceId srcDid = deviceId(uri(pcepTunnel.srcDeviceID()));
321 DeviceId dstDid = deviceId(uri(pcepTunnel.dstDeviceId()));
322 PortNumber srcPort = PortNumber.portNumber(pcepTunnel.srcPort());
323 PortNumber dstPort = PortNumber.portNumber(pcepTunnel.dstPort());
324
325 srcPoint = new DefaultOpticalTunnelEndPoint(id(), Optional.of(srcDid),
326 Optional.of(srcPort), null,
327 endPointType,
328 OpticalLogicId.logicId(0),
329 true);
330 dstPoint = new DefaultOpticalTunnelEndPoint(id(), Optional.of(dstDid),
331 Optional.of(dstPort), null,
332 endPointType,
333 OpticalLogicId.logicId(0),
334 true);
335
336 // basic annotations
337 DefaultAnnotations annotations = DefaultAnnotations.builder()
338 .set("bandWith", String.valueOf(pcepTunnel.bandWidth()))
339 .set("SLA", String.valueOf(pcepTunnel.getSla()))
340 .set("index", String.valueOf(pcepTunnel.id())).build();
341
342 // if (path != null) {
343 //
344 // DefaultAnnotations extendAnnotations = DefaultAnnotations.builder()
345 // .set("pathNum", String.valueOf(hopNum))
346 // // .set("path", pathString)
347 // .set("pathType", String.valueOf(pcepTunnel.getPathType()))
348 // .build();
349 // annotations = DefaultAnnotations.merge(annotations,
350 // extendAnnotations);
351 // }
352
353 // a VLAN tunnel always carry OCH tunnel, this annotation is the index
354 // of a OCH tunnel.
355 if (pcepTunnel.underLayTunnelId() != 0) {
356 DefaultAnnotations extendAnnotations = DefaultAnnotations
357 .builder()
358 .set("underLayTunnelIndex",
359 String.valueOf(pcepTunnel.underLayTunnelId())).build();
360 annotations = DefaultAnnotations.merge(annotations,
361 extendAnnotations);
362
363 }
364 TunnelDescription tunnel = new DefaultTunnelDescription(
365 tunnelId,
366 srcPoint,
367 dstPoint,
368 tunnelType,
369 new DefaultGroupId(
370 0),
371 id(), name,
372 path,
373 annotations);
374 return tunnel;
375
376 }
377
378 /**
379 * Get the tunnelID according to the tunnel key.
380 *
381 * @param tunnelKey tunnel key
382 * @return corresponding tunnel id of the a tunnel key.
383 */
384 private TunnelId getTunnelId(String tunnelKey) {
385
386 for (String key : tunnelMap.keySet()) {
387 if (key.equals(tunnelKey)) {
388 return tunnelMap.get(key);
389 }
390 }
391 return null;
392 }
393
394 /**
395 * Get the tunnel key according to the tunnelID.
396 *
397 * @param tunnelId tunnel id
398 * @return corresponding a tunnel key of the tunnel id.
399 */
400 private String getPCEPTunnelKey(TunnelId tunnelId) {
401 for (String key : tunnelMap.keySet()) {
402 if (tunnelMap.get(key).id() == tunnelId.id()) {
403 return key;
404 }
405 }
406 return null;
407
408 }
409
410 private class InnerTunnerProvider implements PcepTunnelListener {
411
412 @Override
413 public void handlePCEPTunnel(PcepTunnel pcepTunnel) {
414
415 TunnelDescription tunnel = null;
416 // instance and id identify a tunnel together
417 String tunnelKey = String.valueOf(pcepTunnel.getInstance())
418 + String.valueOf(pcepTunnel.id());
419
420 if (tunnelKey == null || "".equals(tunnelKey)) {
421 log.error("Invalid PCEP tunnel");
422 return;
423 }
424
425 TunnelId tunnelId = getTunnelId(tunnelKey);
426
427 tunnel = buildOpticalTunnel(pcepTunnel, tunnelId);
428
429 OperationType operType = pcepTunnel.getOperationType();
430 switch (operType) {
431 case ADD:
432 tunnelId = service.tunnelAdded(tunnel);
433 tunnelMap.put(tunnelKey, tunnelId);
434 break;
435
436 case UPDATE:
437 service.tunnelUpdated(tunnel);
438 break;
439
440 case DELETE:
441 service.tunnelRemoved(tunnel);
442 tunnelMap.remove(tunnelKey);
443 break;
444
445 default:
446 log.error("Invalid tunnel operation");
447
448 }
449
450 }
451 }
452
453 @Override
454 public Tunnel tunnelQueryById(TunnelId tunnelId) {
455 return service.tunnelQueryById(tunnelId);
456 }
457
458}