Updates to the SDN-IP CLI:
* Added command options to show summary of the routes: - "onos:routes -s" or "onos:routes --summary" shows summary of the SDN-IP routes - "onos:bgp-routes -s" or "onos:bgp-routes --summary" shows summary of the BGP routes * Implemented displaying JSON output for the "onos:routes" and "onos:bgp-routes" commands (and the routes summary) Also, added static methods BgpConstants.Update.AsPath.typeToString() and BgpConstants.Update.Origin.typeToString() to return the BGP AS_PATH type and BGP UPDATE ORIGIN type as a string. Change-Id: I505c55a924721838bbbaf4ffccc30ffd61e90120
Showing
4 changed files
with
258 additions
and
30 deletions
... | @@ -119,6 +119,31 @@ public final class BgpConstants { | ... | @@ -119,6 +119,31 @@ public final class BgpConstants { |
119 | 119 | ||
120 | /** BGP UPDATE ORIGIN: INCOMPLETE. */ | 120 | /** BGP UPDATE ORIGIN: INCOMPLETE. */ |
121 | public static final int INCOMPLETE = 2; | 121 | public static final int INCOMPLETE = 2; |
122 | + | ||
123 | + /** | ||
124 | + * Gets the BGP UPDATE origin type as a string. | ||
125 | + * | ||
126 | + * @param type the BGP UPDATE origin type | ||
127 | + * @return the BGP UPDATE origin type as a string | ||
128 | + */ | ||
129 | + public static String typeToString(int type) { | ||
130 | + String typeString = "UNKNOWN"; | ||
131 | + | ||
132 | + switch (type) { | ||
133 | + case IGP: | ||
134 | + typeString = "IGP"; | ||
135 | + break; | ||
136 | + case EGP: | ||
137 | + typeString = "EGP"; | ||
138 | + break; | ||
139 | + case INCOMPLETE: | ||
140 | + typeString = "INCOMPLETE"; | ||
141 | + break; | ||
142 | + default: | ||
143 | + break; | ||
144 | + } | ||
145 | + return typeString; | ||
146 | + } | ||
122 | } | 147 | } |
123 | 148 | ||
124 | /** | 149 | /** |
... | @@ -142,6 +167,28 @@ public final class BgpConstants { | ... | @@ -142,6 +167,28 @@ public final class BgpConstants { |
142 | 167 | ||
143 | /** BGP UPDATE AS_PATH Type: AS_SEQUENCE. */ | 168 | /** BGP UPDATE AS_PATH Type: AS_SEQUENCE. */ |
144 | public static final int AS_SEQUENCE = 2; | 169 | public static final int AS_SEQUENCE = 2; |
170 | + | ||
171 | + /** | ||
172 | + * Gets the BGP AS_PATH type as a string. | ||
173 | + * | ||
174 | + * @param type the BGP AS_PATH type | ||
175 | + * @return the BGP AS_PATH type as a string | ||
176 | + */ | ||
177 | + public static String typeToString(int type) { | ||
178 | + String typeString = "UNKNOWN"; | ||
179 | + | ||
180 | + switch (type) { | ||
181 | + case AS_SET: | ||
182 | + typeString = "AS_SET"; | ||
183 | + break; | ||
184 | + case AS_SEQUENCE: | ||
185 | + typeString = "AS_SEQUENCE"; | ||
186 | + break; | ||
187 | + default: | ||
188 | + break; | ||
189 | + } | ||
190 | + return typeString; | ||
191 | + } | ||
145 | } | 192 | } |
146 | 193 | ||
147 | /** | 194 | /** | ... | ... |
... | @@ -309,7 +309,7 @@ public class BgpRouteEntry extends RouteEntry { | ... | @@ -309,7 +309,7 @@ public class BgpRouteEntry extends RouteEntry { |
309 | @Override | 309 | @Override |
310 | public String toString() { | 310 | public String toString() { |
311 | return MoreObjects.toStringHelper(getClass()) | 311 | return MoreObjects.toStringHelper(getClass()) |
312 | - .add("type", this.type) | 312 | + .add("type", BgpConstants.Update.AsPath.typeToString(type)) |
313 | .add("segmentAsNumbers", this.segmentAsNumbers) | 313 | .add("segmentAsNumbers", this.segmentAsNumbers) |
314 | .toString(); | 314 | .toString(); |
315 | } | 315 | } |
... | @@ -444,7 +444,7 @@ public class BgpRouteEntry extends RouteEntry { | ... | @@ -444,7 +444,7 @@ public class BgpRouteEntry extends RouteEntry { |
444 | .add("prefix", prefix()) | 444 | .add("prefix", prefix()) |
445 | .add("nextHop", nextHop()) | 445 | .add("nextHop", nextHop()) |
446 | .add("bgpId", bgpSession.getRemoteBgpId()) | 446 | .add("bgpId", bgpSession.getRemoteBgpId()) |
447 | - .add("origin", origin) | 447 | + .add("origin", BgpConstants.Update.Origin.typeToString(origin)) |
448 | .add("asPath", asPath) | 448 | .add("asPath", asPath) |
449 | .add("localPref", localPref) | 449 | .add("localPref", localPref) |
450 | .add("multiExitDisc", multiExitDisc) | 450 | .add("multiExitDisc", multiExitDisc) | ... | ... |
... | @@ -15,10 +15,18 @@ | ... | @@ -15,10 +15,18 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.sdnip.cli; | 16 | package org.onlab.onos.sdnip.cli; |
17 | 17 | ||
18 | +import java.util.Collection; | ||
19 | + | ||
20 | +import com.fasterxml.jackson.databind.JsonNode; | ||
21 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
22 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
23 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
18 | import org.apache.karaf.shell.commands.Command; | 24 | import org.apache.karaf.shell.commands.Command; |
25 | +import org.apache.karaf.shell.commands.Option; | ||
19 | import org.onlab.onos.cli.AbstractShellCommand; | 26 | import org.onlab.onos.cli.AbstractShellCommand; |
20 | import org.onlab.onos.sdnip.SdnIpService; | 27 | import org.onlab.onos.sdnip.SdnIpService; |
21 | -import org.onlab.onos.sdnip.bgp.BgpConstants; | 28 | +import org.onlab.onos.sdnip.bgp.BgpConstants.Update.AsPath; |
29 | +import org.onlab.onos.sdnip.bgp.BgpConstants.Update.Origin; | ||
22 | import org.onlab.onos.sdnip.bgp.BgpRouteEntry; | 30 | import org.onlab.onos.sdnip.bgp.BgpRouteEntry; |
23 | 31 | ||
24 | /** | 32 | /** |
... | @@ -27,46 +35,134 @@ import org.onlab.onos.sdnip.bgp.BgpRouteEntry; | ... | @@ -27,46 +35,134 @@ import org.onlab.onos.sdnip.bgp.BgpRouteEntry; |
27 | @Command(scope = "onos", name = "bgp-routes", | 35 | @Command(scope = "onos", name = "bgp-routes", |
28 | description = "Lists all routes received from BGP") | 36 | description = "Lists all routes received from BGP") |
29 | public class BgpRoutesListCommand extends AbstractShellCommand { | 37 | public class BgpRoutesListCommand extends AbstractShellCommand { |
38 | + @Option(name = "-s", aliases = "--summary", | ||
39 | + description = "BGP routes summary", | ||
40 | + required = false, multiValued = false) | ||
41 | + private boolean routesSummary = false; | ||
30 | 42 | ||
31 | - private static final String FORMAT = | 43 | + private static final String FORMAT_SUMMARY = "Total BGP routes = %d"; |
44 | + private static final String FORMAT_ROUTE = | ||
32 | "prefix=%s, nexthop=%s, origin=%s, localpref=%s, med=%s, aspath=%s, bgpid=%s"; | 45 | "prefix=%s, nexthop=%s, origin=%s, localpref=%s, med=%s, aspath=%s, bgpid=%s"; |
33 | 46 | ||
34 | @Override | 47 | @Override |
35 | protected void execute() { | 48 | protected void execute() { |
36 | SdnIpService service = get(SdnIpService.class); | 49 | SdnIpService service = get(SdnIpService.class); |
37 | 50 | ||
38 | - for (BgpRouteEntry route : service.getBgpRoutes()) { | 51 | + // Print summary of the routes |
39 | - printRoute(route); | 52 | + if (routesSummary) { |
53 | + printSummary(service.getBgpRoutes()); | ||
54 | + return; | ||
55 | + } | ||
56 | + | ||
57 | + // Print all routes | ||
58 | + printRoutes(service.getBgpRoutes()); | ||
59 | + } | ||
60 | + | ||
61 | + /** | ||
62 | + * Prints summary of the routes. | ||
63 | + * | ||
64 | + * @param routes the routes | ||
65 | + */ | ||
66 | + private void printSummary(Collection<BgpRouteEntry> routes) { | ||
67 | + if (outputJson()) { | ||
68 | + ObjectMapper mapper = new ObjectMapper(); | ||
69 | + ObjectNode result = mapper.createObjectNode(); | ||
70 | + result.put("totalRoutes", routes.size()); | ||
71 | + print("%s", result); | ||
72 | + } else { | ||
73 | + print(FORMAT_SUMMARY, routes.size()); | ||
74 | + } | ||
75 | + } | ||
76 | + | ||
77 | + /** | ||
78 | + * Prints all routes. | ||
79 | + * | ||
80 | + * @param routes the routes to print | ||
81 | + */ | ||
82 | + private void printRoutes(Collection<BgpRouteEntry> routes) { | ||
83 | + if (outputJson()) { | ||
84 | + print("%s", json(routes)); | ||
85 | + } else { | ||
86 | + for (BgpRouteEntry route : routes) { | ||
87 | + printRoute(route); | ||
88 | + } | ||
40 | } | 89 | } |
41 | } | 90 | } |
42 | 91 | ||
92 | + /** | ||
93 | + * Prints a BGP route. | ||
94 | + * | ||
95 | + * @param route the route to print | ||
96 | + */ | ||
43 | private void printRoute(BgpRouteEntry route) { | 97 | private void printRoute(BgpRouteEntry route) { |
44 | if (route != null) { | 98 | if (route != null) { |
45 | - print(FORMAT, route.prefix(), route.nextHop(), | 99 | + print(FORMAT_ROUTE, route.prefix(), route.nextHop(), |
46 | - originToString(route.getOrigin()), route.getLocalPref(), | 100 | + Origin.typeToString(route.getOrigin()), |
47 | - route.getMultiExitDisc(), route.getAsPath(), | 101 | + route.getLocalPref(), route.getMultiExitDisc(), |
48 | - route.getBgpSession().getRemoteBgpId()); | 102 | + route.getAsPath(), route.getBgpSession().getRemoteBgpId()); |
49 | } | 103 | } |
50 | } | 104 | } |
51 | 105 | ||
52 | - private static String originToString(int origin) { | 106 | + /** |
53 | - String originString = "UNKNOWN"; | 107 | + * Produces a JSON array of routes. |
54 | - | 108 | + * |
55 | - switch (origin) { | 109 | + * @param routes the routes with the data |
56 | - case BgpConstants.Update.Origin.IGP: | 110 | + * @return JSON array with the routes |
57 | - originString = "IGP"; | 111 | + */ |
58 | - break; | 112 | + private JsonNode json(Collection<BgpRouteEntry> routes) { |
59 | - case BgpConstants.Update.Origin.EGP: | 113 | + ObjectMapper mapper = new ObjectMapper(); |
60 | - originString = "EGP"; | 114 | + ArrayNode result = mapper.createArrayNode(); |
61 | - break; | 115 | + |
62 | - case BgpConstants.Update.Origin.INCOMPLETE: | 116 | + for (BgpRouteEntry route : routes) { |
63 | - originString = "INCOMPLETE"; | 117 | + result.add(json(mapper, route)); |
64 | - break; | ||
65 | - default: | ||
66 | - break; | ||
67 | } | 118 | } |
119 | + return result; | ||
120 | + } | ||
121 | + | ||
122 | + /** | ||
123 | + * Produces JSON object for a route. | ||
124 | + * | ||
125 | + * @param mapper the JSON object mapper to use | ||
126 | + * @param route the route with the data | ||
127 | + * @return JSON object for the route | ||
128 | + */ | ||
129 | + private ObjectNode json(ObjectMapper mapper, BgpRouteEntry route) { | ||
130 | + ObjectNode result = mapper.createObjectNode(); | ||
131 | + | ||
132 | + result.put("prefix", route.prefix().toString()); | ||
133 | + result.put("nextHop", route.nextHop().toString()); | ||
134 | + result.put("bgpId", route.getBgpSession().getRemoteBgpId().toString()); | ||
135 | + result.put("origin", Origin.typeToString(route.getOrigin())); | ||
136 | + result.put("asPath", json(mapper, route.getAsPath())); | ||
137 | + result.put("localPref", route.getLocalPref()); | ||
138 | + result.put("multiExitDisc", route.getMultiExitDisc()); | ||
68 | 139 | ||
69 | - return originString; | 140 | + return result; |
70 | } | 141 | } |
71 | 142 | ||
143 | + /** | ||
144 | + * Produces JSON object for an AS path. | ||
145 | + * | ||
146 | + * @param mapper the JSON object mapper to use | ||
147 | + * @param asPath the AS path with the data | ||
148 | + * @return JSON object for the AS path | ||
149 | + */ | ||
150 | + private ObjectNode json(ObjectMapper mapper, BgpRouteEntry.AsPath asPath) { | ||
151 | + ObjectNode result = mapper.createObjectNode(); | ||
152 | + ArrayNode pathSegmentsJson = mapper.createArrayNode(); | ||
153 | + for (BgpRouteEntry.PathSegment pathSegment : asPath.getPathSegments()) { | ||
154 | + ObjectNode pathSegmentJson = mapper.createObjectNode(); | ||
155 | + pathSegmentJson.put("type", | ||
156 | + AsPath.typeToString(pathSegment.getType())); | ||
157 | + ArrayNode segmentAsNumbersJson = mapper.createArrayNode(); | ||
158 | + for (Long asNumber : pathSegment.getSegmentAsNumbers()) { | ||
159 | + segmentAsNumbersJson.add(asNumber); | ||
160 | + } | ||
161 | + pathSegmentJson.put("segmentAsNumbers", segmentAsNumbersJson); | ||
162 | + pathSegmentsJson.add(pathSegmentJson); | ||
163 | + } | ||
164 | + result.put("pathSegments", pathSegmentsJson); | ||
165 | + | ||
166 | + return result; | ||
167 | + } | ||
72 | } | 168 | } | ... | ... |
... | @@ -15,7 +15,14 @@ | ... | @@ -15,7 +15,14 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.sdnip.cli; | 16 | package org.onlab.onos.sdnip.cli; |
17 | 17 | ||
18 | +import java.util.Collection; | ||
19 | + | ||
20 | +import com.fasterxml.jackson.databind.JsonNode; | ||
21 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
22 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
23 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
18 | import org.apache.karaf.shell.commands.Command; | 24 | import org.apache.karaf.shell.commands.Command; |
25 | +import org.apache.karaf.shell.commands.Option; | ||
19 | import org.onlab.onos.cli.AbstractShellCommand; | 26 | import org.onlab.onos.cli.AbstractShellCommand; |
20 | import org.onlab.onos.sdnip.RouteEntry; | 27 | import org.onlab.onos.sdnip.RouteEntry; |
21 | import org.onlab.onos.sdnip.SdnIpService; | 28 | import org.onlab.onos.sdnip.SdnIpService; |
... | @@ -26,22 +33,100 @@ import org.onlab.onos.sdnip.SdnIpService; | ... | @@ -26,22 +33,100 @@ import org.onlab.onos.sdnip.SdnIpService; |
26 | @Command(scope = "onos", name = "routes", | 33 | @Command(scope = "onos", name = "routes", |
27 | description = "Lists all routes known to SDN-IP") | 34 | description = "Lists all routes known to SDN-IP") |
28 | public class RoutesListCommand extends AbstractShellCommand { | 35 | public class RoutesListCommand extends AbstractShellCommand { |
36 | + @Option(name = "-s", aliases = "--summary", | ||
37 | + description = "SDN-IP routes summary", | ||
38 | + required = false, multiValued = false) | ||
39 | + private boolean routesSummary = false; | ||
29 | 40 | ||
30 | - private static final String FORMAT = | 41 | + private static final String FORMAT_SUMMARY = "Total SDN-IP routes = %d"; |
42 | + private static final String FORMAT_ROUTE = | ||
31 | "prefix=%s, nexthop=%s"; | 43 | "prefix=%s, nexthop=%s"; |
32 | 44 | ||
33 | @Override | 45 | @Override |
34 | protected void execute() { | 46 | protected void execute() { |
35 | SdnIpService service = get(SdnIpService.class); | 47 | SdnIpService service = get(SdnIpService.class); |
36 | 48 | ||
37 | - for (RouteEntry route : service.getRoutes()) { | 49 | + // Print summary of the routes |
38 | - printRoute(route); | 50 | + if (routesSummary) { |
51 | + printSummary(service.getRoutes()); | ||
52 | + return; | ||
53 | + } | ||
54 | + | ||
55 | + // Print all routes | ||
56 | + printRoutes(service.getRoutes()); | ||
57 | + } | ||
58 | + | ||
59 | + /** | ||
60 | + * Prints summary of the routes. | ||
61 | + * | ||
62 | + * @param routes the routes | ||
63 | + */ | ||
64 | + private void printSummary(Collection<RouteEntry> routes) { | ||
65 | + if (outputJson()) { | ||
66 | + ObjectMapper mapper = new ObjectMapper(); | ||
67 | + ObjectNode result = mapper.createObjectNode(); | ||
68 | + result.put("totalRoutes", routes.size()); | ||
69 | + print("%s", result); | ||
70 | + } else { | ||
71 | + print(FORMAT_SUMMARY, routes.size()); | ||
72 | + } | ||
73 | + } | ||
74 | + | ||
75 | + /** | ||
76 | + * Prints all routes. | ||
77 | + * | ||
78 | + * @param routes the routes to print | ||
79 | + */ | ||
80 | + private void printRoutes(Collection<RouteEntry> routes) { | ||
81 | + if (outputJson()) { | ||
82 | + print("%s", json(routes)); | ||
83 | + } else { | ||
84 | + for (RouteEntry route : routes) { | ||
85 | + printRoute(route); | ||
86 | + } | ||
39 | } | 87 | } |
40 | } | 88 | } |
41 | 89 | ||
90 | + /** | ||
91 | + * Prints a route. | ||
92 | + * | ||
93 | + * @param route the route to print | ||
94 | + */ | ||
42 | private void printRoute(RouteEntry route) { | 95 | private void printRoute(RouteEntry route) { |
43 | if (route != null) { | 96 | if (route != null) { |
44 | - print(FORMAT, route.prefix(), route.nextHop()); | 97 | + print(FORMAT_ROUTE, route.prefix(), route.nextHop()); |
45 | } | 98 | } |
46 | } | 99 | } |
100 | + | ||
101 | + /** | ||
102 | + * Produces a JSON array of routes. | ||
103 | + * | ||
104 | + * @param routes the routes with the data | ||
105 | + * @return JSON array with the routes | ||
106 | + */ | ||
107 | + private JsonNode json(Collection<RouteEntry> routes) { | ||
108 | + ObjectMapper mapper = new ObjectMapper(); | ||
109 | + ArrayNode result = mapper.createArrayNode(); | ||
110 | + | ||
111 | + for (RouteEntry route : routes) { | ||
112 | + result.add(json(mapper, route)); | ||
113 | + } | ||
114 | + return result; | ||
115 | + } | ||
116 | + | ||
117 | + /** | ||
118 | + * Produces JSON object for a route. | ||
119 | + * | ||
120 | + * @param mapper the JSON object mapper to use | ||
121 | + * @param route the route with the data | ||
122 | + * @return JSON object for the route | ||
123 | + */ | ||
124 | + private ObjectNode json(ObjectMapper mapper, RouteEntry route) { | ||
125 | + ObjectNode result = mapper.createObjectNode(); | ||
126 | + | ||
127 | + result.put("prefix", route.prefix().toString()); | ||
128 | + result.put("nextHop", route.nextHop().toString()); | ||
129 | + | ||
130 | + return result; | ||
131 | + } | ||
47 | } | 132 | } | ... | ... |
-
Please register or login to post a comment