blob: ab8e975a4a7cbed3071d4d42be38f772f6011ebf [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -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 Vachuska781d18b2014-10-27 10:31:25 -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 Vachuska781d18b2014-10-27 10:31:25 -070015 */
Jonathan Hart41349e92015-02-09 14:14:02 -080016package org.onosproject.routing.cli;
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -080017
18import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ArrayNode;
21import com.fasterxml.jackson.databind.node.ObjectNode;
Jonathan Hart0b04bed2014-10-16 16:39:19 -070022import org.apache.karaf.shell.commands.Command;
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -080023import org.apache.karaf.shell.commands.Option;
Brian O'Connorabafb502014-12-02 22:26:20 -080024import org.onosproject.cli.AbstractShellCommand;
Jonathan Hart41349e92015-02-09 14:14:02 -080025import org.onosproject.routing.bgp.BgpInfoService;
26import org.onosproject.routing.bgp.BgpRouteEntry;
27import org.onosproject.routing.bgp.BgpSession;
Jonathan Hart2da1e602015-02-18 19:09:24 -080028import org.onosproject.routing.bgp.BgpConstants;
Jonathan Hart41349e92015-02-09 14:14:02 -080029
30import java.util.ArrayList;
31import java.util.Collection;
Jonathan Hart0b04bed2014-10-16 16:39:19 -070032
33/**
34 * Command to show the routes learned through BGP.
35 */
36@Command(scope = "onos", name = "bgp-routes",
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080037 description = "Lists all BGP best routes")
Jonathan Hart0b04bed2014-10-16 16:39:19 -070038public class BgpRoutesListCommand extends AbstractShellCommand {
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -080039 @Option(name = "-s", aliases = "--summary",
40 description = "BGP routes summary",
41 required = false, multiValued = false)
42 private boolean routesSummary = false;
Jonathan Hart0b04bed2014-10-16 16:39:19 -070043
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080044 @Option(name = "-n", aliases = "--neighbor",
45 description = "Routes from a BGP neighbor",
46 required = false, multiValued = false)
47 private String bgpNeighbor;
48
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080049 private static final String FORMAT_SUMMARY_V4 =
50 "Total BGP IPv4 routes = %d";
51 private static final String FORMAT_SUMMARY_V6 =
52 "Total BGP IPv6 routes = %d";
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080053 private static final String FORMAT_HEADER =
54 " Network Next Hop Origin LocalPref MED BGP-ID";
55 private static final String FORMAT_ROUTE_LINE1 =
56 " %-18s %-15s %6s %9s %9s %-15s";
57 private static final String FORMAT_ROUTE_LINE2 =
58 " AsPath %s";
Jonathan Hart0b04bed2014-10-16 16:39:19 -070059
60 @Override
61 protected void execute() {
Jonathan Hart41349e92015-02-09 14:14:02 -080062 BgpInfoService service = AbstractShellCommand.get(BgpInfoService.class);
Jonathan Hart0b04bed2014-10-16 16:39:19 -070063
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -080064 // Print summary of the routes
65 if (routesSummary) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080066 printSummary(service.getBgpRoutes4(), service.getBgpRoutes6());
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -080067 return;
68 }
69
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080070 BgpSession foundBgpSession = null;
71 if (bgpNeighbor != null) {
72 // Print the routes from a single neighbor (if found)
73 for (BgpSession bgpSession : service.getBgpSessions()) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -080074 if (bgpSession.remoteInfo().bgpId().toString().equals(bgpNeighbor)) {
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080075 foundBgpSession = bgpSession;
76 break;
77 }
78 }
79 if (foundBgpSession == null) {
80 print("BGP neighbor %s not found", bgpNeighbor);
81 return;
82 }
83 }
84
85 // Print the routes
86 if (foundBgpSession != null) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080087 printRoutes(foundBgpSession.getBgpRibIn4(),
88 foundBgpSession.getBgpRibIn6());
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080089 } else {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080090 printRoutes(service.getBgpRoutes4(), service.getBgpRoutes6());
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080091 }
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -080092 }
93
94 /**
95 * Prints summary of the routes.
96 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080097 * @param routes4 the IPv4 routes
98 * @param routes6 the IPv6 routes
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -080099 */
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800100 private void printSummary(Collection<BgpRouteEntry> routes4,
101 Collection<BgpRouteEntry> routes6) {
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800102 if (outputJson()) {
103 ObjectMapper mapper = new ObjectMapper();
104 ObjectNode result = mapper.createObjectNode();
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800105 result.put("totalRoutes4", routes4.size());
106 result.put("totalRoutes6", routes6.size());
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800107 print("%s", result);
108 } else {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800109 print(FORMAT_SUMMARY_V4, routes4.size());
110 print(FORMAT_SUMMARY_V6, routes6.size());
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700111 }
112 }
113
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800114 /**
115 * Prints all routes.
116 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800117 * @param routes4 the IPv4 routes to print
118 * @param routes6 the IPv6 routes to print
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800119 */
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800120 private void printRoutes(Collection<BgpRouteEntry> routes4,
121 Collection<BgpRouteEntry> routes6) {
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800122 if (outputJson()) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800123 ObjectMapper mapper = new ObjectMapper();
124 ObjectNode result = mapper.createObjectNode();
Ray Milkey9d810f62015-02-13 11:20:58 -0800125 result.set("routes4", json(routes4));
126 result.set("routes6", json(routes6));
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800127 print("%s", result);
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800128 } else {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800129 // The IPv4 routes
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800130 print(FORMAT_HEADER);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800131 for (BgpRouteEntry route : routes4) {
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800132 printRoute(route);
133 }
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800134 print(FORMAT_SUMMARY_V4, routes4.size());
135 print(""); // Empty separator line
136 // The IPv6 routes
137 print(FORMAT_HEADER);
138 for (BgpRouteEntry route : routes6) {
139 printRoute(route);
140 }
141 print(FORMAT_SUMMARY_V6, routes6.size());
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800142 }
143 }
144
145 /**
146 * Prints a BGP route.
147 *
148 * @param route the route to print
149 */
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700150 private void printRoute(BgpRouteEntry route) {
151 if (route != null) {
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800152 print(FORMAT_ROUTE_LINE1, route.prefix(), route.nextHop(),
Jonathan Hart2da1e602015-02-18 19:09:24 -0800153 BgpConstants.Update.Origin.typeToString(route.getOrigin()),
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800154 route.getLocalPref(), route.getMultiExitDisc(),
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800155 route.getBgpSession().remoteInfo().bgpId());
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800156 print(FORMAT_ROUTE_LINE2, asPath4Cli(route.getAsPath()));
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700157 }
158 }
159
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800160 /**
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800161 * Formats the AS Path as a string that can be shown on the CLI.
162 *
163 * @param asPath the AS Path to format
164 * @return the AS Path as a string
165 */
166 private String asPath4Cli(BgpRouteEntry.AsPath asPath) {
167 ArrayList<BgpRouteEntry.PathSegment> pathSegments =
168 asPath.getPathSegments();
169
170 if (pathSegments.isEmpty()) {
171 return "[none]";
172 }
173
174 final StringBuilder builder = new StringBuilder();
175 for (BgpRouteEntry.PathSegment pathSegment : pathSegments) {
176 String prefix = null;
177 String suffix = null;
178 switch (pathSegment.getType()) {
Jonathan Hart2da1e602015-02-18 19:09:24 -0800179 case BgpConstants.Update.AsPath.AS_SET:
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800180 prefix = "[AS-Set";
181 suffix = "]";
182 break;
Jonathan Hart2da1e602015-02-18 19:09:24 -0800183 case BgpConstants.Update.AsPath.AS_SEQUENCE:
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800184 break;
Jonathan Hart2da1e602015-02-18 19:09:24 -0800185 case BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE:
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800186 prefix = "[AS-Confed-Seq";
187 suffix = "]";
188 break;
Jonathan Hart2da1e602015-02-18 19:09:24 -0800189 case BgpConstants.Update.AsPath.AS_CONFED_SET:
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800190 prefix = "[AS-Confed-Set";
191 suffix = "]";
192 break;
193 default:
194 builder.append(String.format("(type = %s)",
Jonathan Hart2da1e602015-02-18 19:09:24 -0800195 BgpConstants.Update.AsPath.typeToString(pathSegment.getType())));
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800196 break;
197 }
198
199 if (prefix != null) {
200 if (builder.length() > 0) {
201 builder.append(" "); // Separator
202 }
203 builder.append(prefix);
204 }
205 // Print the AS numbers
206 for (Long asn : pathSegment.getSegmentAsNumbers()) {
207 if (builder.length() > 0) {
208 builder.append(" "); // Separator
209 }
210 builder.append(String.format("%d", asn));
211 }
212 if (suffix != null) {
213 // No need for separator
214 builder.append(prefix);
215 }
216 }
217 return builder.toString();
218 }
219
220 /**
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800221 * Produces a JSON array of routes.
222 *
223 * @param routes the routes with the data
224 * @return JSON array with the routes
225 */
226 private JsonNode json(Collection<BgpRouteEntry> routes) {
227 ObjectMapper mapper = new ObjectMapper();
228 ArrayNode result = mapper.createArrayNode();
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700229
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800230 for (BgpRouteEntry route : routes) {
231 result.add(json(mapper, route));
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700232 }
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800233 return result;
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700234 }
235
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800236 /**
237 * Produces JSON object for a route.
238 *
239 * @param mapper the JSON object mapper to use
240 * @param route the route with the data
241 * @return JSON object for the route
242 */
243 private ObjectNode json(ObjectMapper mapper, BgpRouteEntry route) {
244 ObjectNode result = mapper.createObjectNode();
245
246 result.put("prefix", route.prefix().toString());
247 result.put("nextHop", route.nextHop().toString());
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800248 result.put("bgpId",
249 route.getBgpSession().remoteInfo().bgpId().toString());
Jonathan Hart2da1e602015-02-18 19:09:24 -0800250 result.put("origin", BgpConstants.Update.Origin.typeToString(route.getOrigin()));
Ray Milkey9d810f62015-02-13 11:20:58 -0800251 result.set("asPath", json(mapper, route.getAsPath()));
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800252 result.put("localPref", route.getLocalPref());
253 result.put("multiExitDisc", route.getMultiExitDisc());
254
255 return result;
256 }
257
258 /**
259 * Produces JSON object for an AS path.
260 *
261 * @param mapper the JSON object mapper to use
262 * @param asPath the AS path with the data
263 * @return JSON object for the AS path
264 */
265 private ObjectNode json(ObjectMapper mapper, BgpRouteEntry.AsPath asPath) {
266 ObjectNode result = mapper.createObjectNode();
267 ArrayNode pathSegmentsJson = mapper.createArrayNode();
268 for (BgpRouteEntry.PathSegment pathSegment : asPath.getPathSegments()) {
269 ObjectNode pathSegmentJson = mapper.createObjectNode();
270 pathSegmentJson.put("type",
Jonathan Hart2da1e602015-02-18 19:09:24 -0800271 BgpConstants.Update.AsPath.typeToString(pathSegment.getType()));
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800272 ArrayNode segmentAsNumbersJson = mapper.createArrayNode();
273 for (Long asNumber : pathSegment.getSegmentAsNumbers()) {
274 segmentAsNumbersJson.add(asNumber);
275 }
Ray Milkey9d810f62015-02-13 11:20:58 -0800276 pathSegmentJson.set("segmentAsNumbers", segmentAsNumbersJson);
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800277 pathSegmentsJson.add(pathSegmentJson);
278 }
Ray Milkey9d810f62015-02-13 11:20:58 -0800279 result.set("pathSegments", pathSegmentsJson);
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800280
281 return result;
282 }
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700283}