blob: ae86d2c4a3c013a128a3b0792504afd1800226a1 [file] [log] [blame]
Thomas Vachuska7d693f52014-10-21 19:17:57 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska7d693f52014-10-21 19:17:57 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska7d693f52014-10-21 19:17:57 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska7d693f52014-10-21 19:17:57 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.cli.net;
tom613d8142014-09-11 15:09:37 -070017
tomc65fa112014-10-16 07:48:47 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ArrayNode;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070021import org.apache.karaf.shell.api.action.Argument;
22import org.apache.karaf.shell.api.action.Command;
Ray Milkey0068fd02018-10-11 15:45:39 -070023import org.apache.karaf.shell.api.action.Completion;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070024import org.apache.karaf.shell.api.action.lifecycle.Service;
25import org.apache.karaf.shell.api.action.Option;
Ray Milkey3078fc02015-05-06 16:14:14 -070026import org.onosproject.cli.AbstractShellCommand;
Yuta HIGUCHI33485fb2017-01-25 20:13:30 -080027import org.onosproject.net.DeviceId;
28import org.onosproject.net.DisjointPath;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.net.Link;
30import org.onosproject.net.Path;
Yuta HIGUCHI33485fb2017-01-25 20:13:30 -080031import org.onosproject.net.device.DeviceService;
tom613d8142014-09-11 15:09:37 -070032
33import java.util.Set;
34
Brian O'Connorabafb502014-12-02 22:26:20 -080035import static org.onosproject.cli.net.LinksListCommand.compactLinkString;
36import static org.onosproject.net.DeviceId.deviceId;
tom613d8142014-09-11 15:09:37 -070037
38/**
39 * Lists all shortest-paths paths between the specified source and
40 * destination devices.
41 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070042@Service
tom613d8142014-09-11 15:09:37 -070043@Command(scope = "onos", name = "paths",
44 description = "Lists all shortest-paths paths between the specified source and destination devices")
45public class PathListCommand extends TopologyCommand {
46
tom9eb57fb2014-09-11 19:42:38 -070047 private static final String SEP = "==>";
tom613d8142014-09-11 15:09:37 -070048
49 @Argument(index = 0, name = "src", description = "Source device ID",
50 required = true, multiValued = false)
Ray Milkey0068fd02018-10-11 15:45:39 -070051 @Completion(DeviceIdCompleter.class)
tom613d8142014-09-11 15:09:37 -070052 String src = null;
53
tom9eb57fb2014-09-11 19:42:38 -070054 @Argument(index = 1, name = "dst", description = "Destination device ID",
tom613d8142014-09-11 15:09:37 -070055 required = true, multiValued = false)
Ray Milkey0068fd02018-10-11 15:45:39 -070056 @Completion(DeviceIdCompleter.class)
tom613d8142014-09-11 15:09:37 -070057 String dst = null;
58
Yuta HIGUCHI33485fb2017-01-25 20:13:30 -080059 @Option(name = "--disjoint", description = "Show disjoint Paths")
60 boolean disjoint = false;
61
tom613d8142014-09-11 15:09:37 -070062 @Override
Ray Milkeyd84f89b2018-08-17 14:54:17 -070063 protected void doExecute() {
tom613d8142014-09-11 15:09:37 -070064 init();
Yuta HIGUCHI33485fb2017-01-25 20:13:30 -080065 DeviceService deviceService = get(DeviceService.class);
66 DeviceId srcDid = deviceId(src);
67 if (deviceService.getDevice(srcDid) == null) {
68 print("Unknown device %s", src);
Ayaka Koshibee018a922016-01-19 15:53:37 -080069 return;
70 }
Yuta HIGUCHI33485fb2017-01-25 20:13:30 -080071 DeviceId dstDid = deviceId(dst);
72 if (deviceService.getDevice(dstDid) == null) {
73 print("Unknown device %s", dst);
74 return;
75 }
76 Set<? extends Path> paths;
77 if (disjoint) {
78 paths = service.getDisjointPaths(topology, srcDid, dstDid);
79 } else {
80 paths = service.getPaths(topology, srcDid, dstDid);
81 }
tomc65fa112014-10-16 07:48:47 -070082 if (outputJson()) {
Ray Milkey3078fc02015-05-06 16:14:14 -070083 print("%s", json(this, paths));
tomc65fa112014-10-16 07:48:47 -070084 } else {
85 for (Path path : paths) {
86 print(pathString(path));
Yuta HIGUCHI33485fb2017-01-25 20:13:30 -080087 if (path instanceof DisjointPath) {
88 // print backup right after primary
89 print(pathString(((DisjointPath) path).backup()));
90 }
tomc65fa112014-10-16 07:48:47 -070091 }
tom613d8142014-09-11 15:09:37 -070092 }
tom613d8142014-09-11 15:09:37 -070093 }
94
tom9eb57fb2014-09-11 19:42:38 -070095 /**
tomc65fa112014-10-16 07:48:47 -070096 * Produces a JSON array containing the specified paths.
97 *
Ray Milkey3078fc02015-05-06 16:14:14 -070098 * @param context context to use for looking up codecs
tomc65fa112014-10-16 07:48:47 -070099 * @param paths collection of paths
100 * @return JSON array
101 */
Yuta HIGUCHI33485fb2017-01-25 20:13:30 -0800102 public static JsonNode json(AbstractShellCommand context,
103 Iterable<? extends Path> paths) {
104 ObjectMapper mapper = context.mapper();
tomc65fa112014-10-16 07:48:47 -0700105 ArrayNode result = mapper.createArrayNode();
106 for (Path path : paths) {
Ray Milkey3078fc02015-05-06 16:14:14 -0700107 result.add(LinksListCommand.json(context, path)
108 .put("cost", path.cost())
109 .set("links", LinksListCommand.json(context, path.links())));
Yuta HIGUCHI33485fb2017-01-25 20:13:30 -0800110
111 if (path instanceof DisjointPath) {
112 // [ (primay), (backup), ...]
113 DisjointPath backup = (DisjointPath) path;
114 result.add(LinksListCommand.json(context, backup.backup())
115 .put("cost", backup.cost())
116 .set("links", LinksListCommand.json(context, backup.links())));
117 }
tomc65fa112014-10-16 07:48:47 -0700118 }
119 return result;
120 }
121
122 /**
tom9eb57fb2014-09-11 19:42:38 -0700123 * Produces a formatted string representing the specified path.
124 *
125 * @param path network path
126 * @return formatted path string
127 */
128 protected String pathString(Path path) {
129 StringBuilder sb = new StringBuilder();
130 for (Link link : path.links()) {
131 sb.append(compactLinkString(link)).append(SEP);
132 }
133 sb.delete(sb.lastIndexOf(SEP), sb.length());
134 sb.append("; cost=").append(path.cost());
135 return sb.toString();
tom613d8142014-09-11 15:09:37 -0700136 }
137
138}