blob: 56ad480e6994e9e01bd835429bfbbd5b8dc07810 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.sdnip.cli;
Jonathan Hart0b04bed2014-10-16 16:39:19 -070017
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080018import java.util.ArrayList;
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -080019import java.util.Collection;
20
21import com.fasterxml.jackson.databind.JsonNode;
22import com.fasterxml.jackson.databind.ObjectMapper;
23import com.fasterxml.jackson.databind.node.ArrayNode;
24import com.fasterxml.jackson.databind.node.ObjectNode;
Jonathan Hart0b04bed2014-10-16 16:39:19 -070025import org.apache.karaf.shell.commands.Command;
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -080026import org.apache.karaf.shell.commands.Option;
Brian O'Connorabafb502014-12-02 22:26:20 -080027import org.onosproject.cli.AbstractShellCommand;
28import org.onosproject.sdnip.SdnIpService;
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080029import org.onosproject.sdnip.bgp.BgpConstants.Update;
Brian O'Connorabafb502014-12-02 22:26:20 -080030import org.onosproject.sdnip.bgp.BgpRouteEntry;
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080031import org.onosproject.sdnip.bgp.BgpSession;
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 Radoslavov2ce1c522014-11-07 10:32:37 -080049 private static final String FORMAT_SUMMARY = "Total BGP routes = %d";
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080050 private static final String FORMAT_HEADER =
51 " Network Next Hop Origin LocalPref MED BGP-ID";
52 private static final String FORMAT_ROUTE_LINE1 =
53 " %-18s %-15s %6s %9s %9s %-15s";
54 private static final String FORMAT_ROUTE_LINE2 =
55 " AsPath %s";
Jonathan Hart0b04bed2014-10-16 16:39:19 -070056
57 @Override
58 protected void execute() {
59 SdnIpService service = get(SdnIpService.class);
60
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -080061 // Print summary of the routes
62 if (routesSummary) {
63 printSummary(service.getBgpRoutes());
64 return;
65 }
66
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080067 BgpSession foundBgpSession = null;
68 if (bgpNeighbor != null) {
69 // Print the routes from a single neighbor (if found)
70 for (BgpSession bgpSession : service.getBgpSessions()) {
71 if (bgpSession.getRemoteBgpId().toString().equals(bgpNeighbor)) {
72 foundBgpSession = bgpSession;
73 break;
74 }
75 }
76 if (foundBgpSession == null) {
77 print("BGP neighbor %s not found", bgpNeighbor);
78 return;
79 }
80 }
81
82 // Print the routes
83 if (foundBgpSession != null) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -080084 printRoutes(foundBgpSession.bgpRibIn4().values());
85 printRoutes(foundBgpSession.bgpRibIn6().values());
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -080086 } else {
87 printRoutes(service.getBgpRoutes());
88 }
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -080089 }
90
91 /**
92 * Prints summary of the routes.
93 *
94 * @param routes the routes
95 */
96 private void printSummary(Collection<BgpRouteEntry> routes) {
97 if (outputJson()) {
98 ObjectMapper mapper = new ObjectMapper();
99 ObjectNode result = mapper.createObjectNode();
100 result.put("totalRoutes", routes.size());
101 print("%s", result);
102 } else {
103 print(FORMAT_SUMMARY, routes.size());
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700104 }
105 }
106
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800107 /**
108 * Prints all routes.
109 *
110 * @param routes the routes to print
111 */
112 private void printRoutes(Collection<BgpRouteEntry> routes) {
113 if (outputJson()) {
114 print("%s", json(routes));
115 } else {
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800116 print(FORMAT_HEADER);
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800117 for (BgpRouteEntry route : routes) {
118 printRoute(route);
119 }
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800120 print(FORMAT_SUMMARY, routes.size());
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800121 }
122 }
123
124 /**
125 * Prints a BGP route.
126 *
127 * @param route the route to print
128 */
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700129 private void printRoute(BgpRouteEntry route) {
130 if (route != null) {
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800131 print(FORMAT_ROUTE_LINE1, route.prefix(), route.nextHop(),
132 Update.Origin.typeToString(route.getOrigin()),
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800133 route.getLocalPref(), route.getMultiExitDisc(),
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800134 route.getBgpSession().getRemoteBgpId());
135 print(FORMAT_ROUTE_LINE2, asPath4Cli(route.getAsPath()));
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700136 }
137 }
138
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800139 /**
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800140 * Formats the AS Path as a string that can be shown on the CLI.
141 *
142 * @param asPath the AS Path to format
143 * @return the AS Path as a string
144 */
145 private String asPath4Cli(BgpRouteEntry.AsPath asPath) {
146 ArrayList<BgpRouteEntry.PathSegment> pathSegments =
147 asPath.getPathSegments();
148
149 if (pathSegments.isEmpty()) {
150 return "[none]";
151 }
152
153 final StringBuilder builder = new StringBuilder();
154 for (BgpRouteEntry.PathSegment pathSegment : pathSegments) {
155 String prefix = null;
156 String suffix = null;
157 switch (pathSegment.getType()) {
158 case Update.AsPath.AS_SET:
159 prefix = "[AS-Set";
160 suffix = "]";
161 break;
162 case Update.AsPath.AS_SEQUENCE:
163 break;
164 case Update.AsPath.AS_CONFED_SEQUENCE:
165 prefix = "[AS-Confed-Seq";
166 suffix = "]";
167 break;
168 case Update.AsPath.AS_CONFED_SET:
169 prefix = "[AS-Confed-Set";
170 suffix = "]";
171 break;
172 default:
173 builder.append(String.format("(type = %s)",
174 Update.AsPath.typeToString(pathSegment.getType())));
175 break;
176 }
177
178 if (prefix != null) {
179 if (builder.length() > 0) {
180 builder.append(" "); // Separator
181 }
182 builder.append(prefix);
183 }
184 // Print the AS numbers
185 for (Long asn : pathSegment.getSegmentAsNumbers()) {
186 if (builder.length() > 0) {
187 builder.append(" "); // Separator
188 }
189 builder.append(String.format("%d", asn));
190 }
191 if (suffix != null) {
192 // No need for separator
193 builder.append(prefix);
194 }
195 }
196 return builder.toString();
197 }
198
199 /**
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800200 * Produces a JSON array of routes.
201 *
202 * @param routes the routes with the data
203 * @return JSON array with the routes
204 */
205 private JsonNode json(Collection<BgpRouteEntry> routes) {
206 ObjectMapper mapper = new ObjectMapper();
207 ArrayNode result = mapper.createArrayNode();
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700208
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800209 for (BgpRouteEntry route : routes) {
210 result.add(json(mapper, route));
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700211 }
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800212 return result;
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700213 }
214
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800215 /**
216 * Produces JSON object for a route.
217 *
218 * @param mapper the JSON object mapper to use
219 * @param route the route with the data
220 * @return JSON object for the route
221 */
222 private ObjectNode json(ObjectMapper mapper, BgpRouteEntry route) {
223 ObjectNode result = mapper.createObjectNode();
224
225 result.put("prefix", route.prefix().toString());
226 result.put("nextHop", route.nextHop().toString());
227 result.put("bgpId", route.getBgpSession().getRemoteBgpId().toString());
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800228 result.put("origin", Update.Origin.typeToString(route.getOrigin()));
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800229 result.put("asPath", json(mapper, route.getAsPath()));
230 result.put("localPref", route.getLocalPref());
231 result.put("multiExitDisc", route.getMultiExitDisc());
232
233 return result;
234 }
235
236 /**
237 * Produces JSON object for an AS path.
238 *
239 * @param mapper the JSON object mapper to use
240 * @param asPath the AS path with the data
241 * @return JSON object for the AS path
242 */
243 private ObjectNode json(ObjectMapper mapper, BgpRouteEntry.AsPath asPath) {
244 ObjectNode result = mapper.createObjectNode();
245 ArrayNode pathSegmentsJson = mapper.createArrayNode();
246 for (BgpRouteEntry.PathSegment pathSegment : asPath.getPathSegments()) {
247 ObjectNode pathSegmentJson = mapper.createObjectNode();
248 pathSegmentJson.put("type",
Pavlin Radoslavovdfde7ab2014-12-04 14:06:39 -0800249 Update.AsPath.typeToString(pathSegment.getType()));
Pavlin Radoslavov2ce1c522014-11-07 10:32:37 -0800250 ArrayNode segmentAsNumbersJson = mapper.createArrayNode();
251 for (Long asNumber : pathSegment.getSegmentAsNumbers()) {
252 segmentAsNumbersJson.add(asNumber);
253 }
254 pathSegmentJson.put("segmentAsNumbers", segmentAsNumbersJson);
255 pathSegmentsJson.add(pathSegmentJson);
256 }
257 result.put("pathSegments", pathSegmentsJson);
258
259 return result;
260 }
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700261}